python之copy()与deepcopy()区别

背景

为什么要研究这个问题?

  • 之所以提出这个问题,是因为有这样一个场景,我需要使用两个列表ls_oldls_new分别记录某一组状态在执行前后的值,以此判断执行是否成功。若执行成功,则ls_old=ls_new以保存当前状态
  • 因为采用的是=赋值方式,当执行ls_new.clear()时,ls_old也被清空了
  • 于是这引起了我的兴趣。因为之前学习C++的时候对深浅复制以及指针、引用,有过系统的学习,所以猜想python实现=的方式,应该是创建了引用。但这需要去了解它的实现方式才能证实

看官方解释

官方关于copy的说明
一看之下,明白了,用自己的理解总结出来,如下:

  • python在设计之时,也考虑到对一些可变数据类型(mutable)可能随时需要变更值,但使用传统的=赋值方式,会引起预期之外的数据变动,比如有人希望新的变量名表示的值是独立的,不能因旧变量名对值的更改,而导致新变量的值也被更改
  • =这种赋值方式,就是100%使用的引用 (immutable类型即一旦声明就不可改变值的类型,除外,如int,string,float,tuple,你不能让 5=3)。所谓引用,就是不分配新的内存区域去存储复本,而是给原内存区域起个新的名字(别名)。此时新旧两个变量名(所谓变量名就是内存区域的标识,也是首个字节的地址)表示的是同一块内存区域,通过任何一个变量名更改此区域的值时,另一个的值肯定也变了。这也是我前面背景中遇到的情况
  • copy()使用的是浅复制,举例,variable_new=copy(variable_old) 它直接新开辟一份内存区域,这里简单起个名字memory_block_new,用于存放新变量variable_new,但这里区分两种情况
    • variable_old中的简单数据类型(除list和对象之外的都算),直接拷贝一份放在新内存中,所以,这样的数据类型在copy()之后,是完全不同的独立数据,并不会因新旧变量名对数据的更改而导致另一份也更改
    • list,对象等复合数据,不会开辟新内存,而是将它们的引用,放到memory_block_new内。这里就要警示危险了,通过variable_old对此部分数据做变更时,会影响到variable_new中的此部分值,反之亦然
  • deepcopy()使用的是深复制。这个就比较彻底了,管你是简单数据类型还是复合数据类型,全是一个待遇,开辟一块memory_block_new,一股脑全放进去。variable_new=deepcopy(variable_old)之后,variable_newvariable_old完全脱离关系,从此老死不相往来绝不藕断丝连
    • 注意,官方在说明中也提到了一些问题,如复合数据中如果包含对自身的引用,就可能引发递归对象的产生。以及,有些数据类型本身就设计了一部分数据是用于在新旧变量之间共享的,也会被无脑放到为新变量开辟的内存区域,导致过度复制。但是,但是!这都不叫事儿,我等菜鸟想到的问题,大佬早考虑到了,所以他们已经在实现deecopy()的时候解决这些问题了。至于解决过程的细节,我没看,因为基于目前我的需求,也不需要看,就像王爽老师的建议,大概意思是说,适度的、有目的的‘浅尝辄止’是必备的学习方法

你可能感兴趣的:(Python,python)