1.对象赋值
在了解浅拷贝和深拷贝之前,我们必须搞清楚一个概念:对象的赋值实际上只是简单的对象引用,也就是说,当你创建一个对象,然后把它赋给一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用。它们指向的仍然是同一块地址,可以把它理解为c语言中的指针.
>>> a=[1,2,3,4] >>> id(a) 139867365855600 >>> b=a >>> [id(x) for x in a,b] [139867365855600, 139867365855600] >>>
从结果可以看出,把列表a赋给了变量b,可b的内存空间地址仍然是a的地址,也就是说,只是b单纯的指向了列表a。
2.浅拷贝
hubby通过切片操作拷贝person,wifey通过工厂方法拷贝person.
>>> person=['name',['saving',100]] >>> hubby=person[:] >>> wifey=list(person) >>> wifey ['name', ['saving', 100]] >>> hubby ['name', ['saving', 100]] >>>
来看它们的id值并不相同,说明它们是不相同的对象.
>>> [id(x) for x in person,hubby,wifey] [139867365828944, 139867365856464, 139867365856752]
为hubby和wifey重新命名:
hubby
>>> hubby[0]='hubby' >>> wifey[0]='wifey' >>> print hubby, wifey ['hubby', ['saving', 100]] ['wifey', ['saving', 100]] >>>
然后为改变它们的存款:
>>> hubby[1][1]=50 >>> print hubby, wifey ['hubby', ['saving', 50]] ['wifey', ['saving', 50]]
当我们改变hubby的值时,wifey的值也改变了,这是为什么呢,不是它们属于不同的对象吗,对,它们确实属于不同的对象,先来看看它们各自内部元素的id:
>>> [id(x) for x in hubby] [139867365833104, 139867365855312] >>> [id(x) for x in wifey] [139867365833488, 139867365855312] >>>
有没有恍然大悟呢,大家可以发现,hubby和wifey的第二个元素指向同一个地址,这样修改了hubby ,当然wifey 的值也会改变,但是名字为什么之间互相不影响呢,大家都知道,字符串属于不可变类,当hubby和wifey 重新命名时,会重新开辟空间,用'hubby'和‘wifey’替换'name';
总结一下浅拷贝:对一个对象进行赋值其实是创建了一个类型和原对象,其内容是原来对象元素的引用.打个比方,就像你换了一件衣服,但其穿衣服的人没有变,其内容不变。
注意:序列类型的浅拷贝是默认类型的拷贝,有以下几种方式实施(1):完全切片[:],(2):利用工厂函数list(),dict()等,(3)使用copy模块的copy函数.
3.深拷贝
浅拷贝是只单纯的拷贝了新的对象,其内容不会被复制,那么深拷贝,显而易见就是从外在到本质都会复制。
深拷贝用copy模块的deepcopy()函数:
>>> person=['name',['saving',100]] >>> import copy >>> hubby=copy.deepcopy(person) >>> wifey=copy.deepcopy(person) >>> print hubby,wifey ['name', ['saving', 100]] ['name', ['saving', 100]] >>> hubby[1][1]=50 >>> print hubby,wifey ['name', ['saving', 50]] ['name', ['saving', 100]] >>>
看结果:改变了hubby[1][1]的值,wifey[1][1] 的值并没有改变,说明它们的地址不同,看一下它们的id值:
>>> [id(x) for x in hubby] [139867429551728, 139867365856104] >>> [id(x) for x in wifey] [139867429551728, 139867365855528]