如何将一个Python对象的所有属性复制到另一个?

时间:2014-10-20 14:02:51

标签: python class oop object inheritance

我有两个类,其中一个继承自另一个类:

class DaParent(object):
    name = ''
    number = 0

class DaChild(DaParent):
    additional = ''

我现在创建一个Parent并更改属性:

parent = DaParent()
parent.name = 'papa'
parent.number = 123

从这一点开始,我想创建一个Child,我想在其中复制父项的所有属性。我当然可以这样做:

child = DaChild()
child.name = parent.name
child.number = parent.number

问题在于,在开发过程中,这个类会变得具有相当多的属性,我不会经常想要将属性的手动复制更改为子项。

有没有办法自动将父对象的属性接管到新的子对象中?欢迎所有提示!

[编辑] 只是为了解释为什么我想这样做。我使用Peewee ORM与我的数据库进行交互。我现在想修改一个表(意思是如果记录得到更新,我想保留所有以前的版本)。我打算这样做的方法是创建一个Person类和一个继承自PersonRevision类的Person类。然后,我覆盖peewee save() method,不仅保存Person对象,还将所有属性复制到PersonRevision对象中并保存。因为我永远不会直接与PersonRevision类进行交互,所以我不需要阴影或任何花哨的东西。我只想复制属性并将对象称为save()方法。

2 个答案:

答案 0 :(得分:8)

显而易见的解决方案是使用组合/委派而不是继承:

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

这当然是假设你真的不想要"副本"但"引用"。如果你真的想要一个副本,它也是可能的,但它可能会变得棘手的可变类型:

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

如果这些解决方案都不符合您的需求,请解释您的真实用例 - 您可能遇到XY问题。

[edit]确实接近XY问题。真正的问题是:"如何将peewee.Model的字段复制到另一个peewee.Modelpeewee使用描述符(peewee.FieldDescriptor)来控制对模型字段的访问,并将字段名称和定义存储在模型的_meta.fields字典中,因此最简单的解决方案是迭代源模型的_meta.fields密钥并使用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")

注意:未经测试的代码,从未使用peewee,可能还有更好的事情......

答案 1 :(得分:0)

如果您将要有一个有多个子节点的单个父节点,并且每当父节点更改时都应更新子节点以匹配父节点,则将父节点属性改为类属性,并且&#34 ;复制"给孩子们是自动的。

如果您将有多个父母,并且至少有一些父母会有孩子,有三种选择:

  • 使用委托(让孩子在父母那里查看它不知道的任何事情
  • 使用复制(你现在正在做什么)
  • 使用元类为每个不同的父级创建一个新的父类,然后每个父级都将其属性作为类属性。