在没有__copy__
或__deepcopy__
方法的用户定义类的实例上调用copy.copy
或copy.deepcopy
时,Python保证会发生什么?官方文件在这个问题上令人不安地不明确。函数是否总是只返回同一个类的新实例,其中包含原始对象__dict__
的浅/深副本(或者涉及__slots__
时的等效内容)? CPython,PyPy等之间的行为会有所不同吗? Python 2和3之间的行为有何不同? (忽略旧式类。)什么会使人们需要定义显式__copy__
/ __deepcopy__
方法而不是使用默认行为?
引用显式(优于隐式!)所需的权威性陈述。
答案 0 :(得分:2)
从阅读the copy
module's source以及其他文件中,我确定了以下内容:
在用户定义的新样式类的实例上调用copy
或deepcopy
时,该类没有__copy__
方法并且未注册可调用的copy_reg.pickle
,使用协议2调用实例的__reduce_ex__
方法。object
定义了一个__reduce_ex__
方法,该方法由所有未定义自己的新类继承,所以每个实例都有__reduce_ex__
。
__reduce_ex__
and __reduce__
返回可用于pickle的值,copy
模块使用这些值来模拟unpickling,创建&返回由原始对象的状态构成的新对象。此外,在使用deepcopy
时,对象的状态(具体地说,由__reduce_ex__
/ __reduce__
返回的元组的第三个元素)在将其应用于新对象之前进行递归深度复制。
一些基本测试表明,在一个简单的用户定义类的实例__reduce_ex__(2)
上调用x
会返回(<function __newobj__>, (type(x),), x.__dict__, None, None)
。在Python 2和Python 3中,如果该类没有__setstate__
方法,则copy
模块将执行以下等效操作:
callable, args, state, _, _ = x.__reduce_ex__(2)
y = callable(*args)
if deepcopying:
state = deepcopy(state)
y.__dict__.update(state)
return y
因此,似乎copy
函数在用户定义类的实例上的默认行为确实是有用的&amp;简单的事情,并创建一个新对象与原始对象的状态(可能深)副本。