关于python中深拷贝与浅拷贝问题

时间:2022-05-15 22:16:12

关于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