(import copy)

赋值

对象赋值实际上是简单的对象引用。

也就是说,当你创建一个对象,然后把它赋给另一个变量的时候,Python并没有拷贝这个对象,而是拷贝了这个对象的引用。

例如:

foo1=1.0

foo2=foo1

用操作符is判断时,你可以发现结果是true,是因为python是先创建了一个对象1.0,然后这个对象的引用又被赋值给了foo1和foo2,但是如果是这样:

foo1=1.0

foo2=1.0

这时你会发现,这其实是创建了两个不同的对象,用id()可以发现,二者的地址不同;

其实python还有一个特例,例如:

a=1

b=1

id(a)=id(b),原因是python认为这些小整型是会经常用到的,所以python会缓存一部分小整型。

浅拷贝

序列类型的可以通过三种方式实现浅拷贝,浅拷贝也是默认的拷贝类型:

(1)完全切片操作;([:])

(2)利用工厂函数,比如list(),dict()等;

(3)使用copy模块中的copy()函数。

(然而对于非容器类型没有拷贝这这一说)

用is来看返回0,用==来看返回1。

赋值的结果是他们的身份相同,但是浅拷贝的身份却不同。

“对一个对象进行浅拷贝其实是新创建了一个类型跟原对象一样,其内容是原来对象元素的引用,换句话说,这个拷贝的对象本身是新的,但是它的内容不是”

例:

(这个例子是借用银行账户的案例来讲的)

>>> import copy

>>> person=['name',['saveing',100]]

>>> wife=person[:]

>>> hubb=list(person)

>>> id(person)

43752544

>>> id(wife)

43754120

>>> id(hubb)

43533816

>>> [id(x) for x in hubb]

[2434208, 43752664]

>>> [id(x) for x in wife]

[2434208, 43752664]


>>> hubb[1][1]=100

>>> hubb

['name', ['saveing', 100]]

>>> person

['name', ['saveing', 100]]

>>> wife

['name', ['saveing', 100]]

>>> id(hubb)

43533816

>>> id(person)

43752544

>>> id(wife)

43754120


>>> hubb[0]='asd'

>>> hubb

['asd', ['saveing', 100]]

>>> person

['name', ['saveing', 100]]

>>> wife

['name', ['saveing', 100]]

>>> id(hubb)

43533816

>>> id(person)

43752544

>>> id(wife)

43754120

第1个对象是不可变的(是个字符串类型),而第2个是可变的(一个列表)。正因为如此,当进行浅拷贝时,字符串被显式的拷贝,并新创建了一个字符串对象,而列表元素只是把它的引用复制了一下,并不是它的成员。

假设我们要创建一个联合账户,那这是一个非常棒的方案。但是,如果需要的是两个分离账户,就需要作些改动了。

深拷贝

要得到一个完全拷贝或者说深拷贝——创建一个新的容器对象,包含原有对象元素(引用)全新拷贝的引用——需要copy.deepcopy()函数。

例:

>>> import copy

>>> person = ['name', ['savings', 100.00]]

>>> hubb = person

>>> wife = copy.deepcopy(person)

>>> [id(x) for x in person, hubb, wife]

[12242056, 12242056, 12224232]

>>> hubb[0] = 'joe'

>>> wife[0] = 'jane'

>>> hubb, wife

(['joe', ['savings', 100.0]], ['jane', ['savings', 100.0]])

>>> hubb[1][1] = 50.00

>>> hubb, wife

(['joe', ['savings', 50.0]], ['jane', ['savings', 100.0]])

>>> [id(x) for x in hubb]

[12191712, 11826280]

>>> [id(x) for x in wife]

[12114080, 12224792]


注意:

>>> person = ['name', ('savings', 100.00)]

>>> newPerson = copy.deepcopy(person)

>>> [id(x) for x in person, newPerson]

[12225352, 12226112]

>>> [id(x) for x in person]

[9919616, 11800088]

>>> [id(x) for x in newPerson]

[9919616, 11800088]

(上下部分的地址反映出深拷贝会改变副本的id,而对于其中元素则是id不变,如有改动,就会改变)

以下有几点关于拷贝操作的注意:

第一,非容器类型(比如数字、字符串和其他“原子”类型的对象,像代码、类型和xrange对象等)没有被拷贝一说,浅拷贝是用完全切片操作来完成的。

第二,如果元组变量只包含原子类型对象,对它的深拷贝将不会进行。如果我们把账户信息改成元组类型,那么即便按我们的要求使用深拷贝操作也只能得到一个浅拷贝。

第三,并不是所有的对象都可以安全的复制,例如具有开放式连接的套接字复制到远程计算机就不会执行,这是由于对象的部分内部状态(开放式连接)位于python的领域之外。文件对象是禁止复制领域中的另一个示例。

核心模块:copy

我们刚才描述的浅拷贝和深拷贝操作都可以在copy模块中找到。

其实copy模块中只有两个函数可用:

copy()进行浅拷贝操作;

deepcopy()进行深拷贝操作。

import copy

x = copy.copy(y) # make a shallow copy of y x = copy.deepcopy(y) # make a deep copy of y

(来自帮助文档)


资料来源:

《Python 2.1 宝典》

​http://book.51cto.com/art/200806/77233.htm​​(6.20 *拷贝Python对象、浅拷贝和深拷贝)