I’ve got two classes, of which one inherits from the other:
class DaParent(object): name = '' number = 0 class DaChild(DaParent): additional = ''
I now create a Parent and change the attributes:
parent = DaParent() parent.name = 'papa' parent.number = 123
And from this point, I want to create a Child in which I want to copy all the attributes from the parent. I can of course do this like so:
child = DaChild() child.name = parent.name child.number = parent.number
The thing is that while developing, this class will grow to have a fairly large number of attributes, and I don’t constantly want to change the manual copying of the attributes into the child.
Is there a way to automatically take over the attributes of the parent object into a new child object? All tips are welcome!
[EDIT]
Just to explain the WHY I want to do this. I use the Peewee ORM to interact with my DB. I now want to revision a table (meaning if a record gets updated, I want keep all previous versions). The way I intent to do that is by for example creating a Person
class and a PersonRevision
class which inherits from the Person
class. I then override the peewee save() method to not only save the Person
object, but also copy all attributes into a PersonRevision
object and save that as well. Since I will never actually directly interact with the PersonRevision
class I don’t need shadowing or any fancy stuff. I just want to copy the attributes and call the object its save()
method.
Advertisement
Answer
The obvious solution is to use composition/delegation instead of inheritence:
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 is of course assuming that you dont really want “copies” but “references to”. If you really want a copy it’s also possible but it 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 fit your needs, please explain your real use case – you may have an XY problem.
[edit] Bordering on a XY problem, indeed. The real question is: “How do I copy a peewee.Model
‘s fields into another peewee.Model
. peewee
uses descriptors (peewee.FieldDescriptor
) to control access to model’s fields, and store the fields names and definitions in the model’s _meta.fields
dict, so the simplest solution is to iterate on the source model’s _meta.fields
keys 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
, there’s possibly something better to do…