用户定义的类上的复制模块的默认行为

时间:2015-11-27 22:37:35

标签: python python-3.x language-lawyer python-2.x

在没有__copy____deepcopy__方法的用户定义类的实例上调用copy.copycopy.deepcopy时,Python保证会发生什么?官方文件在这个问题上令人不安地不明确。函数是否总是只返回同一个类的新实例,其中包含原始对象__dict__的浅/深副本(或者涉及__slots__时的等效内容)? CPython,PyPy等之间的行为会有所不同吗? Python 2和3之间的行为有何不同? (忽略旧式类。)什么会使人们需要定义显式__copy__ / __deepcopy__方法而不是使用默认行为?

引用显式(优于隐式!)所需的权威性陈述。

1 个答案:

答案 0 :(得分:2)

从阅读the copy module's source以及其他文件中,我确定了以下内容:

  • 在用户定义的新样式类的实例上调用copydeepcopy时,该类没有__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;简单的事情,并创建一个新对象与原始对象的状态(可能深)副本。