好好学习,天天向上

译|拷贝-浅拷贝与深拷贝

原文:8.17. copy — Shallow and deep copy operations Python中的赋值语句并不拷贝对象,而是创建目标和对象之间的绑定关系。对于那些可变的或包含可变对象的集合来说,有时候需要进行拷贝,以使得一个对象的改变并不会改变另一个对象。这个模块提供常规的浅拷贝操作和深拷贝操作(解释如下)。

接口概述:

copy.copy(x) 返回x的一个浅拷贝 copy.deepcopy(x) 返回x的一个深拷贝 exception copy.error 模块的特定错误

浅拷贝和深拷贝之间的不同仅在于复合对象(即包含其他对象的对象,例如列表或者类实例): * 一个浅拷贝创建一个新的复合对象,然后(尽可能地)插入原始对象中的对象的 引用。 * 一个深拷贝创建一个新的复合对象,然后迭代地插入原始对象中的对象的 拷贝

两个在深拷贝操作中常见的问题(浅拷贝不存在这两个问题): * 递归对象(直接或间接包含自身的一个引用的复合对象)可能导致递归循环 * 由于深拷贝拷贝 一切,因此它可能会过多拷贝。例如,即使在副本之间,管理数据结构也应该被共享。

deepcopy()函数通过以下方式来避免这些问题: * 维护一个当前已拷贝对象的"备忘录"字典 * 允许用户定义的类重写拷贝操作或一组组件拷贝。

这个模块不会拷贝下述类型:模块,方法,堆栈跟踪,堆栈帧,文件,socket,窗口,数组或任何类似类型。 它通过返回不变的原始对象来“拷贝”函数和类(浅拷贝,深拷贝)。这与pickle模块的处理方式兼容。

字典的浅拷贝可以使用dict.copy(),而列表的浅拷贝可以通过将整个列表的切片赋值给它,例如:copied_list = original_list[:]

2.5版本修改:新增拷贝函数。

类可以使用与控制pickling相同的接口来控制拷贝。查看模块pickle的描述以获得关于这些方法的信息。copy模块并不使用copy_reg注册模块。

若想为一个类定义它自己的拷贝实现方式,可以定义特殊的方法 copy()deepcopy()。前者被调用来实现浅拷贝操作;不需要传递额外的参数。后者被调用来实现深拷贝操作;需要传递一个参数,“备忘录”字典。如果 deepcopy()实现需要创建一个组件的深拷贝,它应该调用deepcopy函数,并把这个组件作为第一个参数,“备忘录”字典作为第二个参数传递。

碎碎念

先举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
>>> a = range(0,5)
>>> a.append(range(7,9))
>>> b = a
>>> import copy
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> a
[0, 1, 2, 3, 4, [7, 8]]
>>> b
[0, 1, 2, 3, 4, [7, 8]]
>>> c
[0, 1, 2, 3, 4, [7, 8]]
>>> d
[0, 1, 2, 3, 4, [7, 8]]
>>> a.append(777)
>>> a[5].append('c')
>>> a
[0, 1, 2, 3, 4, [7, 8, 'c'], 777]
>>> b
[0, 1, 2, 3, 4, [7, 8, 'c'], 777]
>>> c
[0, 1, 2, 3, 4, [7, 8, 'c']]
>>> d
[0, 1, 2, 3, 4, [7, 8]]
>>> id(a)
3066904664L
>>> id(b)
3066904664L
>>> id(c)
3066908544L
>>> id(d)
3066904624L
>>> id(a[5])
3066821928L
>>> id(b[5])
3066821928L
>>> id(c[5])
3066821928L
>>> id(d[5])
3066905824L
总结一下: 1. python普通的拷贝只是创建原始对象的一个引用。因此,当对a做了任何改动都会直接影响到b。从id也可以看到,a和b指向的是完全一样的对象。 2. python的浅拷贝会创建一个新的与原始对象类型一样的一个对象,然后对对象中每一个元素创建一个引用。因此,对a中不可变对象做的改动,并不会影响到c;而对a中可变对象做的改动,则会影响到c。从id也可以看到,a和c的指向的是不一样的对象,但是a和c中的元素指向的是完全一样的对象。 3. python的深拷贝是完全复制。它不仅会创建一个新的与原始对象类型一样的一个对象,还会对对象中的每一个元素迭代的创建与之类型一致的元素。因此,对a中的任何元素(可变或不可变)做的改动,都不会影响到d。从id也可以看出,a和d指向的是完全不一样的对象。

请言小午吃个甜筒~~