Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to copy all attributes of one Python object to another?

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.

like image 782
kramer65 Avatar asked Oct 20 '14 14:10

kramer65


People also ask

What does clone () do in Python?

Python – clone() function in wand library clone() function makes an exact copy of the original image. One can use this clone image to manipulate without affecting the original image. clone() is one of the most important function because it helps in safe manipulation of image.

What is the difference between shallow copy and Deepcopy in Python?

A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original. A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.


1 Answers

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...

like image 158
bruno desthuilliers Avatar answered Oct 21 '22 09:10

bruno desthuilliers