实际上,应该根据类的期望行为来决定重写哪个方法(
__copy__
还是
__deepcopy__
)。
一般情况下,copy.deepcopy
可以正常工作,它会递归地复制所有内容,因此只有在有些属性不能被复制(永远不允许)时才需要重写。
另一方面,只有当用户(包括您自己)不希望更改传播到已复制的实例时,才应该定义__copy__
。例如,如果您只是包装了可变类型(如list
)或者将可变类型用作实现细节。
此外,有时不清楚要复制的最小属性集。在这种情况下,我也会重写__copy__
,但可能会在其中引发一个TypeError
,并可能包含一个或多个专用的公共copy
方法。
然而,在我看来,arr
算作实现细节,因此我会覆盖__copy__
:
class T(object):
def __init__(self, x, y):
self.arr = [x, y]
def __copy__(self):
new = self.__class__(*self.arr)
return new
只是为了展示它按预期工作:
from copy import copy, deepcopy
x = T([2], [3])
y = copy(x)
x.arr is y.arr
x.arr[0] is y.arr[0]
x.arr[1] is y.arr[1]
x = T([2], [3])
y = deepcopy(x)
x.arr is y.arr
x.arr[0] is y.arr[0]
x.arr[1] is y.arr[1]
关于期望值的快速说明:
通常用户希望你能够通过将实例传递给构造函数来创建一个最小化的副本(与 __copy__
类似或者完全相同)。例如:
lst1 = [1,2,3,4]
lst2 = list(lst1)
lst1 is lst2
一些Python类型有一个显式的copy
方法,如果存在,应该与__copy__
相同。这将允许显式传递参数(但我还没有看到这种情况下的实际操作):
lst3 = lst1.copy()
lst3 is lst1
如果您的类应该被其他人使用,那么您可能需要考虑以下几点。但是,如果您只想让您的类与
copy.copy
一起使用,那么只需重写
__copy__
即可。