Как избежать нескольких обновлений в списке словарей в Python? - PullRequest
0 голосов
/ 21 марта 2011

У меня есть список из 5 словарей, и когда я обновляю dictionary[0], он также одновременно обновляет dictionary[4].Странно то, что он не является систематическим, и словари кажутся мне независимыми, хотя они имеют одно и то же содержание.

Программа 1 показывает проблему так, как я с ней столкнулся.

Программа 2 показываетспособ обойти с помощью deepcopy, но я чувствую, что это не так умно.

Я хотел бы:

  • Понять причины, почему Программа 1 не работает так, как нужноЯ ожидаю
  • Есть ли лучший (умнее, эффективнее) способ написания Программы 2.

Заранее благодарен за любую обратную связь.

Программа 1 иПрограмма 2 обновляет словари в списке outputDictL.Обновления выполняются с данными, найденными в refLists.outputDictL[0] - это словарь, который имеет ключевые значения из данных.outputDict[4] - это словарь, содержащий словарь, значения ключей которого в нашем примере такие же, как outputDict[0].

Программа 1 и Программа 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, данные1 правильно размещены в 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: данные2 были вставлены как в outputDictL[0], так и в outputDictL[4] каждый раз, когда эти словарибыли обновлены.Чтобы увидеть, что мы ожидаем, вы можете проверить выход Program2.

Program 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: данные2 были вставлены только один раз в каждый словарь.Это то, что мы хотели.

Ответы [ 3 ]

1 голос
/ 21 марта 2011

Значения в обоих словарях одинаковы, потому что python хранит только ссылки на объекты.Когда вы назначаете список значению в двух разных словарях, то, что фактически хранится в этих словарях, является ссылкой на один и тот же список.Таким образом, вы фактически создаете только один список и просто используете ссылку в обоих словарях для изменения единого списка.Вы можете увидеть это поведение в следующем простом примере:

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

Переменные l1 и l2 обе ссылаются на один и тот же фактический список.Причина использования deepcopy ожидаемых результатов заключается в том, что он создает совершенно новый список, заполненный теми же значениями, что и исходный список.

Одна дополнительная заметка о вашей функции addQTime2dict: поскольку вы уже подтвердили, что key не находится в dictionary к тому времени, когда вы вызываете update, это имеет тот же эффект, что и при использовании более простого dictionary[key] = dates

1 голос
/ 21 марта 2011

Вы делитесь ссылкой на список дат между двумя диктовками. Когда вы добавляете список в словарь, вы должны сделать копию, чтобы предотвратить это совместное использование

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
0 голосов
/ 21 марта 2011

Это довольно много кода, но я думаю, что метод 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})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...