Python复制函数传递'字节'对象作为第一个参数

时间:2016-04-25 20:40:49

标签: python inheritance copy arguments

我有一个类,如下所示,继承自datetime.date

class my_class(datetime.date):
    def __new__(cls, arg1=None):
        print ("arg1: ", arg1)
        return super().__new__(cls, 2015, 11, 2)

当我copy(或deepcopy)此类的一个实例时,如下所示

import copy
my_obj = my_class(5)
copy.copy(my_obj)

我得到以下输出

arg1:  5
arg1:  b'\x07\xdf\x0b\x02'

很明显,在执行bytes(或copy)时,一些deepcopy对象作为第一个参数传递。我知道copy函数的工作原理是将参数传递给相关对象的构造函数,以便创建一个相同的对象...那么为什么它会传递这些bytes个对象?

这种行为似乎只在从不可变对象继承时才会发生,因为当我从list对象继承时测试它时,copy函数没有传递bytes对象。 / p>

(注意我上面定义的类是我正在使用的真实类的非常(非常!)简化情况,它也继承自datetime.date

提前致谢

注意

我正在使用Python 3.5.1

1 个答案:

答案 0 :(得分:1)

发生这种情况的原因是内部copydeepcopy使用pickle来促进对象状态序列化。来自docs

  

此模块不复制模块,方法,堆栈跟踪,堆栈帧,文件,套接字,窗口,数组或任何类似类型等类型。它通过返回原始对象来“复制”函数和类(浅和深);这与pickle模块处理这些方式兼容。

     

...

     

实际上,copy模块使用pickle模块中已注册的copyreg函数。

为什么copy需要pickle?这是因为:

  

浅拷贝构造一个新的复合对象,然后(尽可能)将对它的引用插入到原始对象中找到的对象。

为此,copy需要能够理解对象层次结构。 Pickling旨在通过将层次结构映射到标准序列化格式来解决该问题。

这也是字节对象的来源。

  

“Pickling”是将Python对象层次结构转换为字节流的过程,而“unpickling”是反向操作,其中字节流(来自二进制文件或类似字节)对象)被转换回对象层次结构。

看来,无论出于何种原因(也许datetime.date以特殊的方式实现__new__?),unpickling不会再现传递给__new__的整数参数。

为什么呢?我没有世俗的想法。捅了一下,看看你能挖出什么。

解决方案

如果copy()deepcopy()对您行为不端,文档也很清楚该怎么做 - 定义您自己的副本实现!

  

为了让类定义自己的副本实现,它可以定义特殊方法__copy__()__deepcopy__()

     

前者被称为实现浅拷贝操作;没有传递其他参数。

     

调用后者来实现深拷贝操作;它传递了一个参数,即备忘录字典。

     

如果__deepcopy__()实现需要对组件进行深层复制,则应调用deepcopy()函数,并将组件作为第一个参数,将备注字典作为第二个参数。