Python list 进行循环 append() 操作时,如果追加的是可变对象,可用 copy() 进行浅拷贝;如果追加的对象里有嵌套的可变对象,则需用深拷贝 copy.deepcopy() 来解决。赋值、浅拷贝和深拷贝的区别,也是个极易让 Python 初学者掉进去的坑。
如下代码:
a = [] # 空列表
b = { # 准备添加到列表a中的字典
'A': 111,
'B': 222
}
a.append(b)
# 此时打印列表a:[{'A': 111, 'B': 222}]
b['A'] = 333
# 修改字典b后,列表a也发生了变化:[{'A': 333, 'B': 222}]
因为,Python 中对 list 进行 append(x) 操作添加一个对象 x 时,实际上是追加了一个 x 对象的引用。 如果 x 是列表、字典、集合等可变对象,修改 x 值后,list 对象的值也发生变化。
再来试试一个循环 append() 操作:
a = [] # 空列表
b = {} # 空字典
# 用for循环把字典b逐一添加到列表a中
for i in range(3):
b['AAA'] = i + 1
print(b)
a.append(b)
print(a)
# 每次打印字典b,分别为:
# {'AAA': 1}
# {'AAA': 2}
# {'AAA': 3}
# 但最后打印列表a为: [{'AAA': 3}, {'AAA': 3}, {'AAA': 3}],与想象中的不一样。
# 因为每次i递增时都会导致之前的字典中的value发生变化。
# 这里用浅拷贝即可达到想要的效果,如下:
a = [] # 空列表
b = {} # 空字典
for i in range(3):
b['AAA'] = i + 1
a.append(b.copy())
print(a)
# 现在列表a是 [{'AAA': 1}, {'AAA': 2}, {'AAA': 3}]
使用浅拷贝(copy):只会拷贝父对象,不会拷贝对象内部的子对象,如果拷贝的是嵌套的可变对象,则又会出现与上面不同的结果,此时就需要深拷贝了。 copy 模块的 deepcopy (深拷贝)方法,完全拷贝了父对象及其子对象。 如下代码:
a = [] # 空列表
b = { # 嵌套字典
'AAA': {},
}
for i in range(3):
b['AAA']['aaa'] = i + 1
print(b)
a.append(b.copy())
print(a)
# {'AAA': {'aaa': 1}}
# {'AAA': {'aaa': 2}}
# {'AAA': {'aaa': 3}}
# [{'AAA': {'aaa': 3}}, {'AAA': {'aaa': 3}}, {'AAA': {'aaa': 3}}]
# 现在b是个嵌套的字典,使用浅拷贝时没有得到想要的结果。i递增时还是会导致之前的字典中的value发生变化。
# 使用深拷贝即可。需先导入copy模块
import copy
a = [] # 空列表
b = { # 嵌套字典
'AAA': {},
}
for i in range(3):
b['AAA']['aaa'] = i + 1
a.append(copy.deepcopy(b))
print(a)
# 结果:[{'AAA': {'aaa': 1}}, {'AAA': {'aaa': 2}}, {'AAA': {'aaa': 3}}]
最后,复制网上一段关于深拷贝与浅拷贝的区别:
深拷贝是指使用一块新的与原对象相同大小的内存,将需要拷贝的对象的所有值都拷贝到新的内存位置中,拷贝出来的对象与原对象互相独立。使用深拷贝赋值,传的是值。
浅拷贝是指使用原对象的引用作为拷贝的对象,而不使用新的内存存放拷贝出来的对象,拷贝的对象与原对象共用同一块内存,所以对其中任一个做修改,另一个也会随之改变。使用浅拷贝赋值,传的是引用。
参考资料:
» 本文来自:乌帮图 » 《Python append() 添加嵌套的可变对象》
» 链接地址:https://wbt5.com/python-append-deepcopy.html »英雄不问来路,转载请注明出处。