关于python中深拷贝与浅拷贝问题,做个研究小结。
《python核心编程》上说:
以存储模型为标准,类型可以分为:
标量/原子类型 数值(所有的数值类型)、字符串(全部文字)
容器类型 列表、元组、字典
以更新模型为标准,类型可以分为:
可变类型:列表,字典
不可变类型:数字,字符串,元组
可变类型创建后允许值更新,不可变类型创建后不允许值更新。不可变类型创建新对象后若与旧对象重名,就会取代旧对象,比如:
x = 'Hello!' id(x) 32074688 x = 'Hi' id(x) 32014136 i = 0 id(i) 20069076 i = 1 id(i) 20069064
再深入研究就是深拷贝和浅拷贝。
浅拷贝是默认的拷贝类型,序列类型的可以通过三种方式实现浅拷贝:1、完全切片操作;2、利用工厂函数,比如list()等;3、使用copy模块中的copy()函数。对于非容器类型没有拷贝这一说。“对一个对象进行浅拷贝其实是新创建了一个类型跟原对象一样,其内容是原来对象元素的引用,换句话说,这个拷贝的对象本身是新的,但是它的内容不是。”用一个例子作解释:
a = [1,2,[3,4],5] b = list(a) id(a) 32082040 id(b) 32084416 [id(x) for x in a] [20069064, 20069052, 32084576, 20069016] [id(x) for x in b] [20069064, 20069052, 32084576, 20069016]
可以看到b作为浅拷贝创立的新对象,与a的地址不同(id()结果可以认为是内存地址),但是其内容数据的地址却是一致的,符合上述解释。
再进一步分析:
a = [1,2,[3,4],5] b = list(a) a[0] = 100 a [100, 2, [3, 4], 5] b [1, 2, [3, 4], 5] b[0] = 'tt' a [100, 2, [3, 4], 5] b ['tt', 2, [3, 4], 5] a[2][0] = 30 a [100, 2, [30, 4], 5] b ['tt', 2, [30, 4], 5] b[2][1] = 40 b ['tt', 2, [30, 40], 5] a [100, 2, [30, 40], 5]可以看到浅拷贝后的b和原值a之间有某种联系。具体表现在其嵌套结构中数据似乎是引用关系,一个改变,另外一个也跟着改变,例如a[2][0]、b[2][1]更改之后的表现。所以有人说“浅拷贝只能做顶层复制,但是不能复制其嵌套的数据结构。”我觉得这个说法可以接受,至少目前自己找不到更好的解释。
那么如果不想复制数据后还存在这种相互引用关系该怎么办呢?用copy.deepcopy()方法。
import copy a = [1,2,[3,4],5] b = copy.deepcopy(a) a[2][0] = 30 a [1, 2, [30, 4], 5] b [1, 2, [3, 4], 5] b[2][1] = 40 a [1, 2, [30, 4], 5] b [1, 2, [3, 40], 5]
参考:http://www.cnblogs.com/wait123/archive/2011/10/10/2206580.html
http://www.oschina.net/question/872916_84343