【问题标题】:While iterating through a dictionary inside a dictionary, more that one key gets modified despite the break statement在遍历字典中的字典时,尽管有 break 语句,但不止一个键被修改
【发布时间】:2011-11-30 21:57:24
【问题描述】:

我发现了这个非常奇怪的错误,我无法理解。

首先在这个函数里面我解压:

tableOrders = pickle.load(open("\\\\VIERNES7-3\Documentos c\sharedTableOrders.p","rb"))

如果我这样做 pprint(tableOrders) 我会得到:

{1: {'blink': False,
     'canceled': 'no',
     'orders': [{u'availability': u'si',
                 u'canceled': u'no',
                 u'category': u'Minutas',
                 u'kitchen': u'si',
                 u'name': u'Hamburguesa al Plato',
                 u'parilla': u'no',
                 u'price': 60,
                 u'ready': u'no'},
                {u'availability': u'si',
                 u'canceled': u'no',
                 u'category': u'Minutas',
                 u'kitchen': u'si',
                 u'name': u'Hamburguesa al Plato',
                 u'parilla': u'no',
                 u'price': 60,
                 u'ready': u'no'}]}}

现在我以这种方式迭代思想表顺​​序:

count = 0
for x in tableOrders[table]["orders"]:
    if (x["kitchen"] == "si" or x["category"] == "Bebidas") and x["ready"] == "no":
        print count 
        print int(event.widget.curselection()[0]) 
        if count == int(event.widget.curselection()[0]):
                x["ready"] = "si"
                event.widget.delete(int(event.widget.curselection()[0]))
                break
        count += 1

int(event.widget.curselection()[0]) 将成为列表框的选定元素(它似乎工作正常)。

奇怪的是,在我这样做之后,我有:

{1: {'blink': False,
     'canceled': 'no',
     'orders': [{u'availability': u'si',
                 u'canceled': u'no',
                 u'category': u'Minutas',
                 u'kitchen': u'si',
                 u'name': u'Hamburguesa al Plato',
                 u'parilla': u'no',
                 u'price': 60,
                 u'ready': u'si'},       <-------------- MARKED AS "si"
                {u'availability': u'si',
                 u'canceled': u'no',
                 u'category': u'Minutas',
                 u'kitchen': u'si',
                 u'name': u'Hamburguesa al Plato',
                 u'parilla': u'no',
                 u'price': 60,
                 u'ready': u'si'}]}}      <-------------- MARKED AS "si"

所以两个“就绪”都被标记为“si”,这不是我所期望的,因为我已经在那里休息了,如果计数 == 选定的元素,它应该只更改属性“就绪”。

我还尝试单击列表框的第三个元素(索引为 2),这是我从 print countprint int(event.widget.curselection()[0]) 得到的:

0
2
1
2
2
2

这就是我感到困惑的原因,因为只有当两者相等 (2 == 2) 时,x["ready"] = "si" 代码才会被执行。

我不确定问题出在哪里,我很迷茫,但也许我对循环或中断的理解不正确,或者我对如何处理字典感到困惑,x["ready"] = "si" 做了我所期待的其他事情去做。

以防万一,如果我单击列表框的第一个元素(因此int(event.widget.curselection()[0]) 为零),我希望列表的第一个元素为 x["ready"] == "si ",如果我单击第二个,则列表的第二个元素的值应为 "ready" 到 "si",依此类推。

我没有用 gui 标记这个问题,因为据我所知,我已经排除了问题存在的可能性。


编辑:

由于问题似乎出在我在这里使用泡菜时,因此代码更相关:

l = []
for item in sorted(jMenu["menu"]["items"]):
        if item["category"] == selectedCategory:
            l.append(item)
pedido = l[int(widget.curselection()[0])]

##pedido is something like this:
##pedido = {u'category': u'Bebidas', u'price': 40, u'name': u'Coca Cola', u'availability': u'si'}

然后我做:

tableOrders.addFood(activeTable, pedido)

添加食物是

def addFood(self, table, food):
    if not table in self.tableList.keys():
        self.tableList[table] = {"orders":[food], "blink": False, "canceled": "no"}#el canceled hay que sacarlo?
    else:
        self.tableList[table]["orders"].append(food)

我要腌制:

def dumpTableOrders(self):
        tableOrders = pickle.load(open("sharedTableOrders.p","rb"))
        #pprint(self.tableList)

        for food in sorted(self.tableList[activeTable]["orders"]):
            if not activeTable in tableOrders.keys():
                tableOrders[activeTable] = {"orders":[food], "blink": False, "canceled": "no"}#el canceled hay que sacarlo?
            else:
                tableOrders[activeTable]["orders"].append(food)

        self.tableList = {}
        #pprint(tableOrders)
        pickle.dump(tableOrders, open(r'sharedTableOrders.p',"wb"))

【问题讨论】:

  • 看起来这两个字典是同一个对象,也许pickle合并了它们。
  • @CédricJulien 嗯,很有趣,我得回到我“腌制”它们的地方,让你知道。感谢您的建议。
  • 注释掉 GUI 的东西,看看你是否仍然得到相同的结果。
  • @Shog9 我做了,不幸的是结果是一样的。
  • @CédricJulien 好眼力。当我做tableOrders[table]["orders"][0] is tableOrders[table]["orders"][1] 它评估为真。我仍然不确定如何解决它。但至少现在我知道为什么会这样了。

标签: python loops dictionary pickle


【解决方案1】:

问题在于您正在酸洗的对象,当然两个对象都是相同的,例如

>>> import pickle
>>> d = {'name':'same'}
>>> ds = pickle.dumps([d,d])
>>> newd = pickle.loads(ds)
>>> newd[0]['name'] = 'different'
>>> newd
[{'name': 'different'}, {'name': 'different'}]

因此,请查看您正在选择的对象并在那里创建副本,替代方法是 json 转储它,这样您就不会再次获得相同的对象,例如

>>> import json
>>> ds = json.dumps([d,d])
>>> newd = json.loads(ds)
>>> newd[0]['name'] = 'different'
>>> newd
[{u'name': 'different'}, {u'name': u'same'}]

【讨论】:

  • 是的,这似乎正是我的问题,但我不明白你是如何解决的。 (“json dump it”是什么意思我到底应该转储什么?)
  • @Trufa,向我们展示你腌制对象的代码,因为问题出在代码中,而不是在 unpickling 中
  • 我在试试这个,如果成功的话,我会给你建一座纪念碑什么的。
  • 我不知道如何解决的唯一问题是pickle创建了一个文件,这个文件在其他地方的其他模块之间共享。这可以用json吗? (我刚刚看到这是可能的,不过我必须修改很多我的代码库)。我会在一分钟内告诉你。
  • 我做了一个相当肮脏的 hack,但它现在必须工作,我解压,将其转换为 json,然后再次腌制。感谢大家的帮助!
猜你喜欢
  • 2022-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-15
  • 2021-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多