内置函数里有一个copy( )函数,copy标准库里还有一个deepcopy( )函数。从字面理解,一个是拷贝,另一个是深拷贝。那么这两种拷贝有什么区别呢?
看例子。
import copy
l = [1, 2, 3, ['a', 'b', 'c']]
l2 = l # 赋值
l3 = l.copy() # 浅拷贝
l4 = copy.copy(l) # 浅拷贝
l5 = copy.deepcopy(l) # 深拷贝
print('l:', l)
print('l2:', l2)
print('l3:', l3)
print('l4:', l4)
print('l5:', l5)
运行结果:
l: [1, 2, 3, ['a', 'b', 'c']]
l2: [1, 2, 3, ['a', 'b', 'c']]
l3: [1, 2, 3, ['a', 'b', 'c']]
l4: [1, 2, 3, ['a', 'b', 'c']]
l5: [1, 2, 3, ['a', 'b', 'c']]
除了l2是赋值操作之外,l3、l4、l5都是拷贝操作。它们的运行结果完全一样,这也完全符合我们的预期。
下面我们要对列表 l 做一些改变,来看看结果会不会有什么不同。
l.append(4) # 给列表l追加一个元素
print('l:', l, id(l))
print('l2:', l2, id(l2))
print('l3:', l3, id(l3))
print('l4:', l4, id(l4))
print('l5:', l5, id(l5))
运行结果:
l: [1, 2, 3, [‘a’, ‘b’, ‘c’], 4] 4396692336
l2: [1, 2, 3, [‘a’, ‘b’, ‘c’], 4] 4396692336
l3: [1, 2, 3, [‘a’, ‘b’, ‘c’]] 4395820208
l4: [1, 2, 3, [‘a’, ‘b’, ‘c’]] 4396641808
l5: [1, 2, 3, [‘a’, ‘b’, ‘c’]] 4396699888
从运行结果可以看出:
l2这种赋值操作会随着l的改变而改变,因为它们引用的是同一个内存地址。
l3、l4、l5这种拷贝操作,不管是深拷贝还是浅拷贝,都会引用新的对象,也就是内存地址不同。所以,它们不会随着l的改变而改变。
下面继续操作列表l。
l[3].append('d') # 给列表l里面的列表追加一个元素
print('l:', l, id(l[3]))
print('l2:', l2, id(l2[3]))
print('l3:', l3, id(l3[3]))
print('l4:', l4, id(l4[3]))
print('l5:', l5, id(l5[3]))
运行结果为:
l: [1, 2, 3, ['a', 'b', 'c', 'd'], 4] 4507659792
l2: [1, 2, 3, ['a', 'b', 'c', 'd'], 4] 4507659792
l3: [1, 2, 3, ['a', 'b', 'c', 'd']] 4507659792
l4: [1, 2, 3, ['a', 'b', 'c', 'd']] 4507659792
l5: [1, 2, 3, ['a', 'b', 'c']] 4507718032
从运行结果可以看出:
l2这种赋值操作依然会随着l的改变而改变。
l3、l4这种浅拷贝只会拷贝第一层。如果里边的元素有可变元素(比如这两个列表中的列表),可变元素依然会引用原来的对象,也就是它们的内存地址相同。所以,当列表l中的列表改变时,浅拷贝的l3、l4中的列表会随着l的改变而改变。
l5这种深拷贝会完全拷贝一个对象,包括原来对象中的可变元素。
总结
内置的copy函数是浅拷贝,应用的时候需要注意。
浅拷贝只会拷贝第一层。如果被拷贝的对象内有可变元素,那么拷贝出的新对象中的可变元素,依然会引用被拷贝对象中的可变元素。
深拷贝会完全拷贝出一个完全独立的新对象。