0.说明
先看看浅拷贝的概念:
浅拷贝:对一个对象进行浅拷贝其实是新创建了一个类型跟原对象一样,其内容还是原来对象元素的引用,换句话说,这个拷贝的对象本身是新的,但是它的内容不是序列类型对象的浅拷贝是默认类型拷贝,有以下几种实现方式:
完全切片操作:下面操作会有利用工厂函数:比如list()、dict()等
使用copy模块的copy()函数
其实如果是真正理解了Python对象或者说理解了可变对象和不可变对象,再根据上面的理论知识,浅拷贝和深拷贝基本上算是比较好的掌握了。所以这里不按照书上(指的是《Python核心编程》)的思路来进行总结,当然书上的例子作为入门也是非常不错的。下面给出三个例子,如果都可以理解,那么对Python浅拷贝和深拷贝的掌握到这个程度也就可以了。
--------------------------------------------------------------------------------
1.第一个例子:列表中的元素都是原子类型,即不可变对象
>>> person = ['age', 20]
>>> linuxidc = person[:] #浅拷贝
>>> cl = list(person) #浅拷贝
>>> [id(x) for x in person, linuxidc, cl] #虽然是浅拷贝,但是其实也是生成了新的对象
[140205544875144, 140205544893688, 140205544996232]
>>> [id(x) for x in person]
[140205545021232, 32419728]
>>> [id(x) for x in linuxidc]
[140205545021232, 32419728]
>>> [id(x) for x in cl]
[140205545021232, 32419728]
#但是可以看到列表中的元素的还是原来对象元素的引用
上面做了浅拷贝的操作,然后下面修改两个浅拷贝的值:
>>> linuxidc[1] = 22
>>> cl[1] = 21
>>> person, linuxidc, cl
(['age', 20], ['age', 22], ['age', 21])
>>> [id(x) for x in person]
[140205545021232, 32419728]
>>> [id(x) for x in linuxidc]
[140205545021232, 32419680]
>>> [id(x) for x in cl]
[140205545021232, 32419704]
修改了两个浅拷贝的值,然后发现内容并没有相互影响,而且后来的id值也发生改变了,怎么会这样?不要忘了,列表中的元素都是不可变对象,修改不可变对象的值,其实就相当于是新生成了一个该对象,然后让列表元素重新指向新生成的不可变对象,在这里是数字对象。
理解这个例子本身并不难,但需要对Python对象和序列类型本身有一定的理解。
--------------------------------------------------------------------------------
2. 第二个例子:列表中包含容器类型变量,即可变对象
>>> person = ['name', ['age', 20]]
>>> linuxidc = person[:]
>>> cl = list(person)
>>> person, linuxidc, cl
(['name', ['age', 20]], ['name', ['age', 20]], ['name', ['age', 20]])
>>> [id(x) for x in person, linuxidc, cl]
[140205544995944, 140205544893688, 140205544875144]
# 查看大列表的元素id值
>>> [id(x) for x in person, linuxidc, cl]
[140205544996160, 140205544875144, 140205544996520]
>>> [id(x) for x in person]
[140205546176112, 140205544995944]
>>> [id(x) for x in linuxidc]
[140205546176112, 140205544995944]
>>> [id(x) for x in cl]
[140205546176112, 140205544995944]
# 查看小列表的元素id值
>>> [id(x) for x in person[1]]
[140205545021232, 32419680]
>>> [id(x) for x in linuxidc[1]]
[140205545021232, 32419680]
>>> [id(x) for x in cl[1]]
[140205545021232, 32419680]
三个列表的第一个元素的id值都是一样的,这是引用传递,没有什么问题,跟第一个例子类似,因此修改这个值不会有什么问题。但注意看第二个元素,它是一个列表,可以肯定的是,三个列表中的两个元素的id也肯定是相同的,也是引用传递的道理,但现在关键是看第二个元素,也就是这个列表本身,三个大列表(指的是person这个列表)中的这三个小列表的id值都是一样的,于是,浅拷贝对于对象值的影响就会体现出来了,我们尝试去修改其中一个小列表中的值:
>>> linuxidc[1][1] = 22
>>> person, linuxidc, cl
(['name', ['age', 22]], ['name', ['age', 22]], ['name', ['age', 22]])
>>> [id(x) for x in person, linuxidc, cl]
[140205544995944, 140205544893688, 140205544875144]
# 查看大列表的元素id值
>>> [id(x) for x in person]
[140205546176112, 140205544995944]
>>> [id(x) for x in linuxidc]
[140205546176112, 140205544995944]
>>> [id(x) for x in cl]
[140205546176112, 140205544995944]
# 查看小列表的元素id值
>>> [id(x) for x in person[1]]
[140205545021232, 32419680]
>>> [id(x) for x in linuxidc[1]]
[140205545021232, 32419680]
>>> [id(x) for x in cl[1]]
[140205545021232, 32419680]