How can I copy all the attributes of one Python object to another?
I have two classes from which one inherits from the other:
class DaParent(object):
name = ''
number = 0
class DaChild(DaParent):
additional = ''
Now I create a parent element and change the attributes:
parent = DaParent()
parent.name = 'papa'
parent.number = 123
And from now on, I want to create a Child in which I want to copy all the attributes from the parent. I can of course do it like this:
child = DaChild()
child.name = parent.name
child.number = parent.number
The fact is that during development this class will have a fairly large number of attributes, and I do not constantly want to change the manual copying of attributes to the child.
Is there a way to automatically transfer the attributes of the parent to the new child? All advice is appreciated!
[EDIT] Just to explain WHY, I want to do this. I am using Peewee ORM to interact with my DB. Now I want to revise the table (this means that if the record is updated, I want to keep all previous versions). The way I am going to do this is to create a class Person
and a class PersonRevision
that inherits from the class Person
. Then I override the peewee save () method to not only save the object Person
, but copy all the attributes to the object PersonRevision
and Save that as well. Since I will never interact directly with the class PersonRevision
, I don't need shadows or any fancy stuff. I just want to copy the attributes and call the object with my method save()
.
source to share
The obvious solution is to use composition / delegation instead of inheritance:
class Parent(object):
def __init__(self, name, number):
self.name = name
self.number = number
class Child(object):
def __init__(self, parent, other):
self.parent = parent
self.other = other
def __getattr__(self, name):
try:
return getattr(self.parent, name)
except AttributeError, e:
raise AttributeError("Child' object has no attribute '%s'" % name)
p = Parent("Foo", 42)
c = Child(p, "parrot")
print c.name, c.number, c.other
p.name = "Bar"
print c.name, c.number, c.other
This, of course, assumes that you don't really want "copies" but "links to". If you really want a copy, this is also possible, but can get tricky with mutable types:
import copy
class Parent(object):
def __init__(self, name, number):
self.name = name
self.number = number
class Child(object):
def __init__(self, parent, other):
# only copy instance attributes from parents
# and make a deepcopy to avoid unwanted side-effects
for k, v in parent.__dict__.items():
self.__dict__[k] = copy.deepcopy(v)
self.other = other
If none of these solutions suit your needs, please explain your real-world use case - you might have a problem with XY.
[edit] Actually the problem is with XY. The real question is, "How to copy fields peewee.Model
to another peewee.Model
. peewee
Uses descriptors ( peewee.FieldDescriptor
) to control access to model fields and store the field names and definitions in the _meta.fields
dict model , so the simplest solution is to iterate on the original model _meta.fields
and use getattr
/ setattr
:
class RevisionMixin(object):
@classmethod
def copy(cls, source, **kw):
instance = cls(**kw)
for name in source._meta.fields:
value = getattr(source, name)
setattr(instance, name, value)
return instance
class Person(peewee.Model):
# fields defintions here
class PersonRevision(Person, RevisionMixin):
# additional fields definitions here
p = Person(name="foo", number=42)
r = PersonRevision.copy(p, whatelse="parrot")
NB: untested code, never used peewee
, maybe something better to do ...
source to share
If you have one parent with multiple children and the children need to be updated to match the parent when the parent changes, then the parent attributes will be class attributes instead, and the "copy" for the children will be automatic.
If you have multiple parents and at least some of the parents will have children, there are three options:
- use delegation (have a child in the parent for everything it doesn't know about
- use copy (what are you doing now)
- use metaclasses to create a new parent class for every other parent, then every parent has its attributes as class attributes.
source to share