Python中向字典添加多列表时覆盖原有列表项的问题排查
问题解决:字典中所有键被最后一个列表覆盖
问题描述
我是软件和Python新手,已经花了好几个小时排查问题,搜了各种资料还是没解决。我有一个包含3个双元素列表的字典,需要把这些列表元素和计算出的物品位置相加,填充到第二个字典里,预期能得到3n个列表项。我用嵌套循环加临时列表tempList实现,打印临时列表的时候结果是对的,但最后字典forbiddenAreas里所有键都被最后一个列表覆盖了。试调整赋值语句位置、用update方法都没用,代码如下:
pitch = 100 numberItems = 3 forbiddenAreaItem = { "area1": [21, 25], "area2": [-21, -25], "area3": [12, 15] } forbiddenAreas = {} tempList = [] if numberItems == 1: # print("There is one item") firstItemDistance = 0 else: # print("There are multiple items") firstItemDistance = ((numberItems / 2) - 0.5) * pitch key = 1 for i in range(numberItems): itemLocation = firstItemDistance - pitch * i for y in forbiddenAreaItem: tempList.clear() for x in forbiddenAreaItem[y]: tempList.append(itemLocation + x) forbiddenAreas[key] = tempList print("adding" ,str(tempList), "with key", str(key)) key += 1 print(forbiddenAreas)
问题原因
列表是Python中的可变对象,你全程复用同一个tempList对象:每次调用tempList.clear()只是清空列表里的内容,并没有创建新的列表实例。字典forbiddenAreas中所有键存储的都是这个tempList的引用,所以当最后一次修改tempList后,所有键都会指向这个最终修改后的列表,导致看起来所有值都被最后一个列表覆盖。
解决方案
方案1:每次循环创建新的临时列表
把tempList.clear()换成tempList = [],这样每次内层循环都会生成一个全新的列表对象,字典中的每个键都会指向独立的列表,不会互相影响。
修改后的代码:
pitch = 100 numberItems = 3 forbiddenAreaItem = { "area1": [21, 25], "area2": [-21, -25], "area3": [12, 15] } forbiddenAreas = {} if numberItems == 1: firstItemDistance = 0 else: firstItemDistance = ((numberItems / 2) - 0.5) * pitch key = 1 for i in range(numberItems): itemLocation = firstItemDistance - pitch * i for y in forbiddenAreaItem: tempList = [] # 每次循环创建新列表 for x in forbiddenAreaItem[y]: tempList.append(itemLocation + x) forbiddenAreas[key] = tempList print("adding" ,str(tempList), "with key", str(key)) key += 1 print(forbiddenAreas)
方案2:用列表推导式直接生成新列表
省去临时变量,直接用列表推导式生成新列表并赋值给字典的键,代码更简洁高效:
pitch = 100 numberItems = 3 forbiddenAreaItem = { "area1": [21, 25], "area2": [-21, -25], "area3": [12, 15] } forbiddenAreas = {} if numberItems == 1: firstItemDistance = 0 else: firstItemDistance = ((numberItems / 2) - 0.5) * pitch key = 1 for i in range(numberItems): itemLocation = firstItemDistance - pitch * i for y in forbiddenAreaItem: # 直接通过列表推导生成新列表 forbiddenAreas[key] = [itemLocation + x for x in forbiddenAreaItem[y]] print("adding" ,str(forbiddenAreas[key]), "with key", str(key)) key += 1 print(forbiddenAreas)
内容的提问来源于stack exchange,提问作者xray911
相关产品推荐
相关产品推荐

