最近在用Python进行爬虫解析时,遇到一个比较恼人的bug,归根结底是对Python中的深浅拷贝理解不够透彻。在这里记录下来以供将来查阅。
首先放一段代码:这段代码的功能是遍历列表中的元素对字典键值对中的值依次修改并将新的字典添加到dic_list这个列表中。
dic_list = []
lis = [1, 2, 3]
dic = {}
for ele in lis:
dic["a"] = 1
dic["b"] = 2
dic["c"] = ele
print dic
dic_list.append(dic)
print dic_list
输出结果为:
{'a': 1, 'c': 1, 'b': 2}
{'a': 1, 'c': 2, 'b': 2}
{'a': 1, 'c': 3, 'b': 2}
[{'a': 1, 'c': 3, 'b': 2}, {'a': 1, 'c': 3, 'b': 2}, {'a': 1, 'c': 3, 'b': 2}]
可以看到,每次输出的字典确实被改变了,但是添加新的字典后得到的字典列表却和预期的输出结果不一样,它包含的3个字典元素一模一样。这是怎么回事呢?
原因在于Python中的一切数据类型皆为object,不管是primitive types(int, float, str, bool)还是dict,list,tuple。在添加到列表中时,实际上添加的是指向该字典的引用。而Python中,字典是可变的,在字典被改变后,指向该字典的引用所对应的内容也会改变,所以得到的dic_list中的字典都是第3次循环得到的字典。可以通过添加两条语句得到我们想要的结果:
dic_list = []
lis = [1, 2, 3]
dic = {}
for ele in lis:
dic["a"] = 1
dic["b"] = 2
dic["c"] = ele
new_dic = dic.copy()
dic_list.append(new_dic)
print dic_list
输出结果为:
[{'a': 1, 'c': 1, 'b': 2}, {'a': 1, 'c': 2, 'b': 2}, {'a': 1, 'c': 3, 'b': 2}]
其中,copy()方法用于返回字典的浅拷贝。至于深浅拷贝,等有时间再做整理~
网友评论