【问题标题】:dict() in for loop - different behaviorfor 循环中的 dict() - 不同的行为
【发布时间】:2019-03-09 19:17:08
【问题描述】:

我正在尝试使用 for 循环动态更新 dict() 键的值。

def update_dict():
    f = []
    for i, j in enumerate(list_range):
        test_dict.update({'a': i})
        j['c'] = test_dict
        print(j)
        f.append(j)
    print(f)

test_dict = dict({'a': 1})
list_range = [{'b': i} for i in range(0, 5)]
update_dict()

即使print(j) 给出了迭代值(0,1,2,3,4),不知何故最后一个字典被整个列表覆盖并给出错误的输出(4,4,4,4,4)

预期输出,

[{'b': 0, 'c': {'a': 0}}, {'b': 1, 'c': {'a': 1}}, {'b': 2, 'c': {'a': 2}}, {'b': 3, 'c': {'a': 3}}, {'b': 4, 'c': {'a': 4}}]

获得的输出,

[{'b': 0, 'c': {'a': 4}}, {'b': 1, 'c': {'a': 4}}, {'b': 2, 'c': {'a': 4}}, {'b': 3, 'c': {'a': 4}}, {'b': 4, 'c': {'a': 4}}]

我需要了解字典是如何被覆盖的,以及避免这种情况的最佳解决方案是什么?

提前致谢!

附: :请避免建议列表或字典理解方法作为我所知道的简单答案,这个问题的唯一目的是理解 dict() 的错误行为。

【问题讨论】:

  • test_dict 对于所有字典都是相同的。随时更新它会更新所有子字典。
  • @Jean-FrançoisFabre 在调试时我看到每次迭代都有不同的值
  • 当然可以,但是之前存储的所有值都被更改了
  • 那么 dict.update() 会更新列表中的所有值吗?
  • j['c'] 不会创建任何新值,它指向单个对象 test_dict。将此添加到您的脚本中,j['c'] = test_dict, id(test_dict) 并查看该函数之外的单个 dict 对象。

标签: python json dictionary for-loop


【解决方案1】:

这种行为的原因是列表中的所有引用都指向同一个字典。 j['c'] = test_dict 行不创建字典副本,只是让 j['c'] 引用 test_dict。要获得预期结果,您需要将此行更改为: j['c'] = test_dict.copy()。它将制作 test_dict 的深层副本并将其分配给 j['c']。

【讨论】:

    【解决方案2】:

    您每次都尝试在循环中将值添加到同一个字典中,并且随着循环的进行,您会不断替换这些值。

    您需要在每次迭代中定义字典以创建字典的单独引用:

    def update_dict():
        f = []
        for i, j in enumerate(list_range):
            test_dict = {'a': i}
            j['c'] = test_dict
            f.append(j)
        print(f)
    
    
    list_range = [{'b': i} for i in range(0, 5)]
    update_dict()
    
    # [{'b': 0, 'c': {'a': 0}}, 
    #  {'b': 1, 'c': {'a': 1}},
    #  {'b': 2, 'c': {'a': 2}},
    #  {'b': 3, 'c': {'a': 3}},
    #  {'b': 4, 'c': {'a': 4}}]
    

    【讨论】:

    • 你是对的,我的错,看看你的代码可以简化
    • 太棒了!这工作正常。但是如果 test_dict 包含更多像 test_dict = dict({'a': 1, 'b':'c'}) 这样的键并且我不想改变 'b' 怎么办?
    • 所以你可以在循环中添加test_dict = {'a': i, 'b': 'c'}b 的值将始终为 c
    • 我给出的问题只是示例代码。在最初我的test_dict 可能包含几个键,我需要更新其中的任何一个键。恐怕我无法在我的用例中使用您的建议。
    • @SmashGuy 是的,你可以这样做。见我之前的评论。在那里,只有键 achanges 的值,但另一个保持不变。
    【解决方案3】:

    更简单的解决方案是遍历list_range 并使用b 中的值创建c

    lista = [{'b': i } for i in range(0, 5)]
    for i in lista:
        i['c'] = {'a': i['b']}
    # [{'b': 0, 'c': {'a': 0}}, {'b': 1, 'c': {'a': 1}}, {'b': 2, 'c': {'a': 2}}, {'b': 3, 'c': {'a': 3}}, {'b': 4, 'c': {'a': 4}}]
    

    【讨论】:

      【解决方案4】:
      def update_dict():
         f = []
         for i, j in enumerate(list_range):
              j['c'] = {'a': i}
              print(j)
              f.append(j)
         return f
      
      list_range = [{'b': i} for i in range(0, 5)]
      print(update_dict())
      
      #output
      {'b': 0, 'c': {'a': 0}}
      {'b': 1, 'c': {'a': 1}}
      {'b': 2, 'c': {'a': 2}}
      {'b': 3, 'c': {'a': 3}}
      {'b': 4, 'c': {'a': 4}}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-11
        • 2019-05-26
        • 1970-01-01
        • 2021-09-25
        相关资源
        最近更新 更多