(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对象、浅拷贝和深拷贝)