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

Default behavior of copy module on user-defined classes

当在没有__copy____deepcopy__方法的用户定义class实例上调用copy.copy or copy.deepcopy时,Python 保证会怎样?令人不安的是,官方文档在这个问题上并不明确。该函数是否总是 return 同一个 class 的新实例与原始对象的 __dict__ 的 shallow/deep 副本(或者当 __slots__参与)? CPython、PyPy 等之间的行为会有所不同吗? Python 2 和 3 之间的行为是否不同? (忽略旧式 classes。)什么需要定义明确的 __copy__/__deepcopy__ 方法而不是使用默认行为?

参考显式(比隐式好!)需要权威声明。

通过阅读 the copy module's source,以及其他文档,我确定了以下内容:

  • copydeepcopy 在没有 __copy__ 的用户定义新样式 class 的实例上调用时方法并且没有注册一个可调用的 copy_reg.pickle, the instance's __reduce_ex__ 方法被调用协议 2. object 定义了一个 __reduce_ex__ 方法,它被所有新式 classes 继承不要自己定义,所以每个实例都有一个__reduce_ex__.

  • __reduce_ex__ and __reduce__ return 可用于 pickling 的值,copy 模块使用这些值来模拟 unpickling,创建并 returning 一个新对象由原始对象的状态制成。此外,当使用 deepcopy 时,对象的状态(具体来说,由 __reduce_ex__/__reduce__ 编辑的元组 return 的第三个元素)在应用到新对象之前被递归地深度复制对象.

  • 一些基本测试表明,在简单用户定义的 class returns [=28= 的实例 x 上调用 __reduce_ex__(2) ].在 Python 2 和 Python 3 中,如果 class 没有 __setstate__ 方法,那么 copy 模块将执行以下等效操作:

    callable, args, state, _, _ = x.__reduce_ex__(2)
    y = callable(*args)
    if deepcopying:
        state = deepcopy(state)
    y.__dict__.update(state)
    return y
    

所以看来 copy 函数在用户定义 classes 实例上的默认行为确实是做有用且简单的事情并创建一个新对象(可能deep) 原始对象状态的副本。