本帖最后由 Galois 于 2019-3-27 19:00 编辑
在Python的学习过程中,经常会遇到对象的拷贝问题,一般来说,Python中的复制对象的方法有三种:赋值、浅拷贝与深拷贝。下面来谈一下个人见解。
1、赋值
Python中的赋值语句相当于用一个变量给另一个变量赋值,相当于给当前内存中的对象增加一个“标签”而已。从下面的例子中可以看出x,y的内存地址一样,指向同一个对象。
>>> x = [1, 2, 3]
>>> y = x
>>> print(id(x), id(y))
2939292384712 2939292384712
2、浅拷贝
注意:浅拷贝和深拷贝的不同仅仅是对组合对象来说,所谓的组合对象就是包含了其它对象的对象,如列表,类实例。而对于数字、字符串以及其它“原子”类型,没有拷贝一说,产生的都是原对象的引用。
浅拷贝创建一个新的复合对象,然后用原对象中子对象的引用来填充它,从本质上讲,浅拷贝只有一层深拷贝。赋值过程不会递归创建子对象的副本。
常见的浅拷贝有:切片操作、工厂函数、对象的copy()方法、copy模块中的copy函数。
>>> import copy
>>> x = [1, [2,3,4]]
>>> y = copy.copy(x)
>>> y
[1, [2, 3, 4]]
>>> id(x)
2603109144648
>>> id(y)
2603109144840
>>> for a, b in zip(x, y):
print(id(a), id(b))
1835428608 1835428608
2603109143240 2603109143240
从上面可以看出,x浅拷贝得到y,x和y指向内存中不同的地址。但它们的元素都指向相同的内存的地址。这就是浅拷贝。
3、深拷贝 深拷贝就是构造一个新的复合对象,然后递归地将复制对象插入到新对象中。深拷贝出来的对象与原对象没有任何关联。
>>> import copy
>>> x = [1, [2, 3, 4]]
>>> y = copy.deepcopy(x)
>>> print(id(x), id(y))
2939292443336 2939292443592
>>> for a, b in zip(x, y):
print(id(a), id(b))
1835428608 1835428608
2939292384328 2939292444744
看了上面的例子,有人可能会疑惑:
为什么使用了深拷贝,a和b中元素的id还是一样呢?
答:这是因为对于不可变对象,当需要一个新的对象时,python可能会返回已经存在的某个类型和值都一致的对象的引用。而且这种机制并不会影响 x 和 y 的相互独立性,因为当两个元素指向同一个不可变对象时,对其中一个赋值不会影响另外一个。
总结:1、赋值:简单地拷贝对象的引用,两个对象的id相同。
2、浅拷贝:创建一个新的组合对象,这个新对象与原对象共享内存中的子对象。
3、深拷贝:创建一个新的组合对象,同时递归地拷贝所有子对象,新的组合对象与原对象没有任何关联。虽然实际上会共享不可变的子对象,但不影响它们的相互独立性。 浅拷贝和深拷贝的不同仅仅是对组合对象来说,所谓的组合对象就是包含了其它对象的对象,如列表,类实例。而对于数字、字符串以及其它“原子”类型,没有拷贝一说,产生的都是原对象的引用。
|