首页推荐互联网科技程序员

Python的对象拷贝

2017-03-05  本文已影响284人  大蟒传奇

对象拷贝

在面向对象编程中,复制一个现有对象的副本,被称为对象拷贝。生成的对象被称之为对象副本。
拷贝是基本的操作,但是在实际操作过程中会有一些需要注意的地方。有多种方法来拷贝对象,最常见的是通过拷贝构造函数或者克隆函数。拷贝的主要目的是对副本做出修改、移动,或者是保留当前值。
如果不需要实现以上目的,则创建对原始数据的引用是更加高效的选择。

Python的对象拷贝

在Python中,赋值语句总是建立对象的引用,看下面的一段代码

>>> a = [1,2,3]
>>> b = a
>>> print(id(a), id(b))
(4420030688, 4420030688)

会发现b = a操作后,ab指向了同一块地址。

上面例子中,ab都是可变对象(list)的,对b的修改,同样可会影响到a,如下

>>> b.append(3)
>>> a
[1, 2, 3, 3]

那么对于可变的数据的副本,或者包含了可变对象的数据的副本,如何在不改变原数据的情况下操作副本呢?这里就要用到内置的copy模块了。

浅拷贝

浅拷贝

在浅拷贝中,会将原对象中所有字段复制给对象副本。如果某个字段是某个对象的引用(比如,一串内存地址),那么被拷贝的是这个引用,指向元数据中该字段指向的对象;如果字段是基本类型,则复制这个字段的值。

在Python这样万物皆是对象的语言中,使用浅拷贝后,对象副本中字段和原始数据中字段都会指向同一个对象,这样的情况下,引用的对象被共享,因此,如果这些对象中的一个被修改,则改变在另外一个中可见。浅拷贝很简单,可以通过简单的完全复制位来实现,所以开销也很小。

比如下面的例子。

>>> a = [[1,2,3], [1,2], [1]]
>>> id(a), id(a[0]), id(a[1]), id(a[2])
(4420406880, 4420406448, 4420406808, 4420406304)
>>> b = copy.copy(a)
>>> id(b), id(b[0]), id(b[1]), id(b[2])
(4420423760, 4420406448, 4420406808, 4420406304)

深拷贝

深拷贝

另一种方法是深拷贝,这意味着原对象中的字段被解引用。和浅拷贝不同,引用不再被拷贝,而是会为引用的值创建新的对象。也就是说对于副本的改变不会影响到原始数据。copy模块中的deepcopy函数可以实现这一点。

>>> import copy
>>> l1 = [2, 3, 4, [3, 5]]
>>> l2 = copy.deepcopy(l1)
>>> l1, l2
([2, 3, 4, [3, 5]], [2, 3, 4, [3, 5]])
>>> l2[3].append(6)
>>> l2.append(7)
>>> l1, l2
([2, 3, 4, [3, 5]], [2, 3, 4, [3, 5, 6], 7])

总结

Python中copy模块通过copy()deepcopy()函数来分别提供浅拷贝和深拷贝功能。程序员可以通过在对象中定义__copy__()__deepcopy()__方法来修改模块默认的实现。

上一篇下一篇

猜你喜欢

热点阅读