【问题标题】:Python: how to implement copy for base class which works for inherited with new attributesPython:如何为使用新属性继承的基类实现复制
【发布时间】:2018-05-28 11:31:54
【问题描述】:

如何实现基类的复制,该复制适用于继承的新属性而没有为继承的类实现__copy__(意味着新属性的哑副本)?

即我们有一个包含一个用户定义和一个计算(或外部参考,不应复制)字段的类。所以副本应该创建实例,仅基于用户定义的字段:

class A(object):
    def __init__(self, a):
        self.a = a
        self.b = a+1

    def __copy__(self):
        return A(self.a)

此时copy 工作正常。

然后我们引入继承类,它的构造函数根据它自己的args计算基构造函数的args,并且还引入了新字段,所以继承构造函数的签名是完全不同的并且对于基类是未知的(共同的):

class B(A):
    def __init__(self, c):
        A.__init__(self, c+100)
        self.c=c

此时copy 显然工作不正常,返回A 实例。当然,我们可以为继承的类实现自己的__copy__,但是当我们引入一些属性时,这非常不方便,应该以普通方式复制。所以我想要实现的是,通过A.__copy__ 复制继承类B 的“A 部分”,但仍保留标准副本,无需为所有继承类重新实现__copy__。那么对于这种情况是否有任何“设计模式”?

更新: 我想将示例从copy 重新表述为deepcopy,这更接近实际情况。所以这个想法是一样的——我们必须管理 A 类的深度复制,它包含不应该被深度复制的引用(即链接到容器,其中包含对象)。但我们不想管理继承类的深度复制。

from copy import deepcopy

class A:

    def __init__(self, content, container):
        self.content = content
        self.container = container

    def __deepcopy__(self, memo):
        return A(deepcopy(self.content, memo), self.container)

class B(A):

    def __init__(self, attr):
        A.__init__(self, [1,2,3], self)
        self.attr = attr

b = B(123)
b1=deepcopy(b) # wrong!

看起来我找到了适合我的特定情况的模式(谢谢@mhawke):首先复制所有内容,然后只深度复制必要的字段。

class A:
    def __deepcopy__(self, memo):
        o = copy(self)
        o.content = deepcopy(self.content)
        return o

但它不能解决常见情况下的问题:对于 deepcopy,我想对继承的属性进行 deepcopy,而不是复制它,并且仅在必要时管理 deepcoping 以进行覆盖。

【问题讨论】:

  • copy.copy() 有什么问题?它将继承类的对象复制到同一类的实例中。
  • 我想在这种特殊情况下没有错。也许更好地考虑 deepcopy,在很多情况下应该覆盖基类 deepcopy 以排除处理某些链接,即链接到某些列表中的相邻对象。问题是如何实现基类副本,这对于典型的重写工作正常。

标签: python design-patterns


【解决方案1】:

对于您的示例,这将起作用-您“仅”必须覆盖 _copyattrs-,现在我不确定这是否比仅覆盖 __copy__ 更好。

class A(object):
    _copyattrs = ["a"]

    def __copy__(self):
        args = [getattr(self, attrname) for attrname in self._copyattrs]
        return type(self)(*args) 


class B(A):
    _copyattrs = ["c"]

【讨论】:

  • 不太好,因为我们只需要一些覆盖。我想要实现的是基类将为整个类调用一些“标准”复制过程,但由基类“A”管理的部分除外。
猜你喜欢
  • 1970-01-01
  • 2011-12-08
  • 1970-01-01
  • 2020-08-09
  • 1970-01-01
  • 2014-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多