开发者

How to avoiding multiple updates in a list of dictionaries in Python?

I have a list of 5 dictionaries, and when I am updating dictionary[0], it also simultaneously updates dictionary[4]. The strange thing is that it is not systematic, and the dictionaries seem independent to me, although they share the same 开发者_运维问答content.

Program 1 shows the problem as I encountered it.

Program 2 shows a way to work around by using deepcopy, but I feel it is not so smart.

I would like to:

  • Understand reasons why Program 1 does not work the way I expect
  • Are there any better (smarter, more efficient) way to write Program 2.

Thanks in advance for any feed back.

Program 1 and Program 2 update dictionaries in the list outputDictL. Updates are performed with data found in refLists. outputDictL[0] is a dictionary that has its key values from the data. outputDict[4] is a dictionary that contains a dictionary whose key values are in our example the same as outputDict[0].

Program 1 and Program 2 and almost the same. The difference is that in Program 2 I am using a deep copy of the dictionary for the function argument rather then its reference.

Program 1

Program 1 source code:

#!/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"

Program 1 output:

-------------------
--- 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']}}]
-------------------

This works as we expect. f1, data1 are correctly placed in outputDictL[0] and 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']}}]
-------------------

This is not what we expected : f1 : data2 has been inserted in both outputDictL[0] and in outputDictL[4] each time those dictionaries were updated. To see what we are expecting you may check Program2 output.

Program 2

Program 2 source code :

#!/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 output:

-------------------
--- 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 has been inserted only once in each dictionary. This is what we wanted.


The values in both dictionaries are the same because python only stores references to objects. When you assign a list to a value in two different dictionaries, what's actually stored in those dictionaries is a reference to the same list. So you only actually create one list and just use the reference in both dictionaries to modify the single list. You can see this behavior in the following simple example:

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

The variables l1 and l2 both refer to the same actual list. The reason using deepcopy produces the expect results is that it creates an entirely new list populated with the same values as the original list.

One extra note on your addQTime2dict function: because you have already confirmed that key is not in dictionary by the time you call update, it has the same effect as using the simpler dictionary[key] = dates


You are sharing a reference to the dates list between the two dicts. When you add the list to the dictionary you should make a copy to prevent this sharing

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


That's quite a bit of code, but I think the dict.has_key() method is what will fix your problem. For example, in your first listing:

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})
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜