【问题标题】:How to avoiding multiple updates in a list of dictionaries in Python?如何避免在 Python 中的字典列表中进行多次更新?
【发布时间】:2011-03-20 22:32:59
【问题描述】:

我有一个包含 5 个字典的列表,当我更新 dictionary[0] 时,它也会同时更新 dictionary[4]。奇怪的是它不是系统的,而且字典对我来说似乎是独立的,虽然它们共享相同的内容。

程序 1 显示了我遇到的问题。

程序 2 展示了一种使用 deepcopy 的解决方法,但我觉得它不是那么聪明。

我想:

  • 了解程序 1 无法按预期方式运行的原因
  • 有没有更好(更智能、更高效)的方法来编写程序 2。

提前感谢您的任何反馈。

程序 1 和程序 2 更新列表 outputDictL 中的字典。使用在refLists 中找到的数据执行更新。 outputDictL[0] 是一个字典,其键值来自数据。 outputDict[4] 是一个字典,其中包含一个字典,其键值在我们的示例中与 outputDict[0] 相同。

Program 1 和Program 2 几乎一样。不同之处在于,在程序 2 中,我将字典的深层副本用于函数参数,而不是其引用。

程序 1

程序1源码:

#!/usr/bin/python
# -*- coding: ISO-8859-15 -*-
# Id: $
L1 = "   "
import copy
##A dds one qTime item to a dictionary
# dates is an array
def addQTime2dict(dictionary, key, dates):
   #"%s       k %s, v: %s"%(L6, key, value)
   print "%s adding key : %s dates : %s"%(L1, key, dates)
   if key in dictionary :
      dictionary[key].extend(dates)
   else :
      dictionary.update({key : dates})

## updates all dictionaries
def updateDicts(outputDictL, S, D, fqdn, dates):
   print "--- fqdn : %s, dates : %s"%(fqdn, dates)
   print "- Before updating Dict[0]\n%s outputDictL : %s"%(L1, outputDictL)
   addQTime2dict(outputDictL[0], fqdn, dates)
   print "- After updating Dict[0]\n%s outputDictL : %s"%(L1, outputDictL)
   if D not in outputDictL[4] :
      outputDictL[4][D] = {}
   print "- Before updating Dict[4]\n%s outputDictL : %s"%(L1, outputDictL)
   addQTime2dict(outputDictL[4][D], fqdn, dates)
   print "- After updating Dict[4]\n%s outputDictL : %s"%(L1, outputDictL)
outputDictL = map( lambda x : {} , range(5))

refList = [("S1", "D1", "f1", "data1"), ("S2", "D1", "f1", "data2")]

for l in refList :
   print "-------------------"
   updateDicts(outputDictL, l[0], l[1], l[2], [l[3]])
   print "-------------------\n"

程序1输出:

-------------------
--- fqdn : f1, dates : ['data1']
- Before updating Dict[0]
    outputDictL : [{}, {}, {}, {}, {}]
    adding key : f1 dates : ['data1']
- After updating Dict[0]
    outputDictL : [{'f1': ['data1']}, {}, {}, {}, {}]
- Before updating Dict[4]
    outputDictL : [{'f1': ['data1']}, {}, {}, {}, {'D1': {}}]
    adding key : f1 dates : ['data1']
- After updating Dict[4]
    outputDictL : [{'f1': ['data1']}, {}, {}, {}, {'D1': {'f1': ['data1']}}]
-------------------

这符合我们的预期。 f1、data1正确放置在outputDictL[0]outputDictL[4]

-------------------
--- fqdn : f1, dates : ['data2']
- Before updating Dict[0]
    outputDictL : [{'f1': ['data1']}, {}, {}, {}, {'D1': {'f1': ['data1']}}]
    adding key : f1 dates : ['data2']
- After updating Dict[0]
    outputDictL : [{'f1': ['data1', 'data2']}, {}, {}, {}, {'D1': {'f1': ['data1', 'data2']}}]
- Before updating Dict[4]
    outputDictL : [{'f1': ['data1', 'data2']}, {}, {}, {}, {'D1': {'f1': ['data1', 'data2']}}]
    adding key : f1 dates : ['data2']
- After updating Dict[4]
    outputDictL : [{'f1': ['data1', 'data2', 'data2']}, {}, {}, {}, {'D1': {'f1': ['data1', 'data2', 'data2']}}]
-------------------

这不是我们所期望的:每次更新这些字典时,f1 : data2 都被插入到 outputDictL[0]outputDictL[4] 中。要查看我们的预期,您可以查看 Program2 输出。

程序 2

程序2源代码:

#!/usr/bin/python
# -*- coding: ISO-8859-15 -*-
# Id: $ 
L1 = "   "
import copy
##A dds one qTime item to a dictionary
# dates is an array
def addQTime2dict(dictionary, key, dates):
   #"%s       k %s, v: %s"%(L6, key, value)
   print "%s adding key : %s dates : %s"%(L1, key, dates)
   if key in dictionary :
      dictionary[key].extend(dates)
   else :
      dictionary.update({key : dates})
   return dictionary

## updates all dictionaries
def updateDicts(outputDictL, S, D, fqdn, dates):
   print "--- fqdn : %s, dates : %s"%(fqdn, dates)
   print "- Before updating Dict[0]\n%s outputDictL : %s"%(L1, outputDictL)
   outputDictL[0] =  addQTime2dict(copy.deepcopy(outputDictL[0]), fqdn, dates)
   print "- After updating Dict[0]\n%s outputDictL : %s"%(L1, outputDictL)
   if D not in outputDictL[4] :
      outputDictL[4][D] = {}
   print "- Before updating Dict[4]\n%s outputDictL : %s"%(L1, outputDictL)
   outputDictL[4][D] = addQTime2dict(copy.deepcopy(outputDictL[4][D]), fqdn, dates)
   print "- After updating Dict[4]\n%s outputDictL : %s"%(L1, outputDictL)

outputDictL = map( lambda x : {} , range(5))

refList = [("S1", "D1", "f1", "data1"), ("S2", "D1", "f1", "data2")]

for l in refList :
   print "-------------------"
   updateDicts(outputDictL, l[0], l[1], l[2], [l[3]])
   print "-------------------\n"

Program2 输出:

-------------------
--- fqdn : f1, dates : ['data1']
- Before updating Dict[0]
    outputDictL : [{}, {}, {}, {}, {}]
    adding key : f1 dates : ['data1']
- After updating Dict[0]
    outputDictL : [{'f1': ['data1']}, {}, {}, {}, {}]
- Before updating Dict[4]
    outputDictL : [{'f1': ['data1']}, {}, {}, {}, {'D1': {}}]
    adding key : f1 dates : ['data1']
- After updating Dict[4]
    outputDictL : [{'f1': ['data1']}, {}, {}, {}, {'D1': {'f1': ['data1']}}]
-------------------

-------------------
--- fqdn : f1, dates : ['data2']
- Before updating Dict[0]
    outputDictL : [{'f1': ['data1']}, {}, {}, {}, {'D1': {'f1': ['data1']}}]
    adding key : f1 dates : ['data2']
- After updating Dict[0]
    outputDictL : [{'f1': ['data1', 'data2']}, {}, {}, {}, {'D1': {'f1': ['data1']}}]
- Before updating Dict[4]
    outputDictL : [{'f1': ['data1', 'data2']}, {}, {}, {}, {'D1': {'f1': ['data1']}}]
    adding key : f1 dates : ['data2']
- After updating Dict[4]
    outputDictL : [{'f1': ['data1', 'data2']}, {}, {}, {}, {'D1': {'f1': ['data1', 'data2']}}]
-------------------

f1 : data2 在每个字典中只插入一次。这就是我们想要的。

【问题讨论】:

  • 发布完整的程序、调试语句及其输出等是不礼貌的。
  • 这比很多问题都没有显示任何代码或输出要好,但最好是尽可能地把它去掉。即使您不知道问题出在哪里,也请尝试删除部分程序。作为奖励,您通常会自己确定问题。
  • 感谢@Apalala 和@Winston 的评论。我认为调试语句和输出可能会有所帮助。下次我会努力做得更好!

标签: python dictionary


【解决方案1】:

两个字典中的值是相同的,因为 python 只存储对对象的引用。当您将列表分配给两个不同字典中的值时,这些字典中实际存储的是对同一列表的引用。因此,您实际上只创建了一个列表,并且只需使用两个字典中的引用来修改单个列表。您可以在以下简单示例中看到此行为:

>>> l1 = []
>>> l2 = l1
>>> l2.append('item')
>>> l1
['item']
>>> l2
['item']

变量 l1 和 l2 都引用同一个实际列表。使用deepcopy 产生预期结果的原因是它创建了一个全新的列表,其中填充了与原始列表相同的值。

关于addQTime2dict函数的一个额外说明:因为您在调用update时已经确认key不在dictionary中,它与使用更简单的dictionary[key] = dates具有相同的效果

【讨论】:

  • 感谢您的回答!我正在寻找字典之间的参考问题,而不是值!太感谢了!我还检查了 dictionary[key] = dates vs dictionary.update() 和 dictionary[key] = dates 似乎快了两倍。感谢您的提示。
【解决方案2】:

您正在两个字典之间共享对日期列表的引用。当您将列表添加到字典中时,您应该制作一份副本以防止这种共享

def addQTime2dict(dictionary, key, dates):
   #"%s       k %s, v: %s"%(L6, key, value)
   print "%s adding key : %s dates : %s"%(L1, key, dates)
   if key in dictionary:
      dictionary[key].extend(dates)
   else:
      dictionary[key] = dates[:] # copy of dates

【讨论】:

  • 感谢您的回答!以这种方式复制日期似乎比使用 copy.deepcopy 快 10 倍以上。谢谢你的提示!
【解决方案3】:

这是相当多的代码,但我认为 dict.has_key() 方法可以解决您的问题。例如,在您的第一个列表中:

def addQTime2dict(dictionary, key, dates):
   #"%s       k %s, v: %s"%(L6, key, value)
   print "%s adding key : %s dates : %s"%(L1, key, dates)
   if dictionary.has_key(key):
      dictionary[key].extend(dates)
   else :
      dictionary.update({key : dates})

【讨论】:

  • has_key 是一个已弃用的函数。它已被 Daniel 使用的 key in dict 语法取代。
  • 它不仅被弃用,而且丝毫没有解决问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-12-06
  • 2015-09-24
  • 2019-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-16
相关资源
最近更新 更多