「Python」深拷贝和浅拷贝

内置函数里有一个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这种深拷贝会完全拷贝一个对象,包括原来对象中的可变元素。

总结

  1. 内置的copy函数是浅拷贝,应用的时候需要注意。

  2. 浅拷贝只会拷贝第一层。如果被拷贝的对象内有可变元素,那么拷贝出的新对象中的可变元素,依然会引用被拷贝对象中的可变元素。

  3. 深拷贝会完全拷贝出一个完全独立的新对象。

你可能感兴趣的:(「Python」深拷贝和浅拷贝)