【问题标题】:Python dictionary changes when using intermediate variable使用中间变量时 Python 字典发生变化
【发布时间】:2015-08-17 08:20:58
【问题描述】:

我正在为函数提供一个字符串,该函数逐个字符地读取字符串。根据正在处理的字符,从字典中调用 JSON 模板,稍加编辑并保存到最终字典,该字典将被解析为 JSON 并保存。

问题是这个模板字典应该保持不变,但事实并非如此。不知何故,我写入中间变量的值被保存到原始模板字典中,弄乱了我试图保存的后续数据。

我是否缺少字典的一些基本概念?这是我第一次以如此程度的方式使用字典,所以我什至不会感到惊讶。

模板字典:

self.map_legend = {"#": {"Id": 100, "Alive": False, "X": 0, "Y": 0, "Width": 1, "Height": 1, "Type": "Wall", "PlayerNumber": 0},
              "-": {"Id": 200, "Alive": False, "X": 0, "Y": 0, "Width": 1, "Height": 1, "Type": "Shield", "PlayerNumber": 0},
              "x": {"Id": 300, "Alive": False, "X": 0, "Y": 0, "Width": 1, "Height": 1, "Type": "Alien", "PlayerNumber": 0},
              "|": {"Id": 400, "Alive": False, "X": 0, "Y": 0, "Width": 1, "Height": 1, "Type": "AlienBullet", "PlayerNumber": 0},
              "!": {"Id": 500, "Alive": False, "X": 0, "Y": 0, "Width": 1, "Height": 1, "Type": "Missile", "PlayerNumber": 0},
              "i": {"Id": 500, "Alive": False, "X": 0, "Y": 0, "Width": 1, "Height": 1, "Type": "Missile", "PlayerNumber": 1},
              "M": {"Id": 600, "Alive": False, "X": 0, "Y": 0, "Width": 3, "Height": 1, "Type": "MissileController", "PlayerNumber": 0},
              "X": {"Id": 700, "Alive": False, "X": 0, "Y": 0, "Width": 3, "Height": 1, "Type": "AlienFactory", "PlayerNumber": 0},
              "A": {"Id": 800, "Alive": False, "X": 0, "Y": 0, "Width": 3, "Height": 1, "Type": "Ship", "PlayerNumber": 0},
              "V": {"Id": 800, "Alive": False, "X": 0, "Y": 0, "Width": 3, "Height": 1, "Type": "Ship", "PlayerNumber": 1},
              " ": {"Id": 900, "Alive": False, "X": 0, "Y": 0, "Width": 1, "Height": 1, "Type": "Space", "PlayerNumber": 0}}

问题代码:

for char in self.initial_game_map:
    if char != "\n":
        element = self.map_legend[char]
        self.id_counters[char] += 1

        element["Id"] = self.id_counters[char] + element["Id"]
        element["Alive"] = True
        element["X"] = char_counter % self.state_json["Map"]["Height"]
        element["Y"] = char_counter / self.state_json["Map"]["Height"]
        print self.map_legend[char]
        print element

        row.append(element)
        element = {}
        char_counter += 1

    else:
        self.state_json["Map"]["Rows"].append(row)
        row = []

一些输出:

V
{'Width': 3, 'PlayerNumber': 1, 'Y': 1, 'X': 2, 'Type': 'Ship', 'Id': 801, 'Alive': True, 'Height': 1}
{'Width': 3, 'PlayerNumber': 1, 'Y': 1, 'X': 2, 'Type': 'Ship', 'Id': 801, 'Alive': True, 'Height': 1}
#
{'Width': 1, 'PlayerNumber': 0, 'Y': 0, 'X': 18, 'Type': 'Wall', 'Id': 103, 'Alive': True, 'Height': 1}
{'Width': 1, 'PlayerNumber': 0, 'Y': 0, 'X': 18, 'Type': 'Wall', 'Id': 103, 'Alive': True, 'Height': 1}

element 变量的行为与预期相同,但您可以看到 self.map_legend 在更改 element 后出于某种原因假定了 element 的值,这不是我想要的。怎么回事?

【问题讨论】:

    标签: python json dictionary


    【解决方案1】:

    elementself.map_legend[char] 指向同一个字典,因此如果您更新element,您将更新字典self.map_legend[char] 的值。您似乎想要一份副本,因此请使用:

    element = self.map_legend[char].copy()
    

    python 文档中的参考:https://docs.python.org/2/library/copy.html。由于字典很浅,你不需要.deepcopy()

    【讨论】:

    • 谢谢,它有效。我怀疑它可能是这样的,但不确定。
    • @Jaycee 经过 17 年的 Python 编程,它有时仍然会咬我。顺便说一句,在使用列表时应采取同样的谨慎态度。在这种情况下使用newlist = oldlist[:](只要列表很浅)。
    • 感谢您的提示 :) 究竟是什么让列表/字典“深”?
    • @Jaycee (可能有官方定义),但经验法则是:如果任何值(在字典或列表中)需要(浅)复制本身,则它很深(即这样的值是一个列表、一个字典、一个类的实例)
    【解决方案2】:

    你需要deepcopy字典,否则原文会被修改。

    from copy import deepcopy
    
    element = deepcopy(self.map_legend[char])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-07-29
      • 2020-11-17
      • 1970-01-01
      • 1970-01-01
      • 2019-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多