首页 > 解决方案 > 遍历列表上的字典更新所有元素而不是当前元素

问题描述

我正在通过列表理解生成一个字典列表,该列表理解只是根据输入参数重复元素 x 次scope_1

当我遍历这个字典列表时,我会向其中添加一些新的键和值。但是,它不是只更新迭代内列表的当前元素,而是更新列表中的所有元素(字典),所以我最终得到所有元素都具有与上次循环执行相同的数据。

为了检查我是否正确地创建了列表,我手动硬编码重新创建了它并添加为我的函数的第二个返回scope_2,这个新列表工作正常。但我看不出这两个列表之间有任何不同的行为。

def get_test_scope(request):
    repeat = request

    test_object = {}
    # Reads from file
    test_object["id"] = "ID-1"
    test_object["summary"] = "Summary-1"

    # Scope 1 from list comprehension
    scope_1 = [test_object for _ in range(repeat)]

    # Scope 2 created manually
    scope_2 = [
        {"id": "ID-2", "summary": "Summary-2"},
        {"id": "ID-2", "summary": "Summary-2"},
    ]
    return scope_1, scope_2


if __name__ == "__main__":
    import random
    # how many times to replicate element inside list
    scope_1, scope_2 = get_test_scope(2)

    # Prints Scope 1 and Scope 2
    print(f"Scope_1: {scope_1}")
    print(f"Scope_2: {scope_2}")

    # Iterates over Scope 1 and add new key, value pairs to it
    # FAIL: Should update only current test element. But updates all the elements of the list in each iteration
    for index, test in enumerate(scope_1):
        test["run"] = index
        test["duration"] = random.randint(1, 10)
        print(f"Scope 1: Loop({index}): {scope_1}")

    # Iterates over Scope 2 and add new key, value pairs to it
    # OK: Adds only to the current test element. Items end it up with their respective values
    for index, test in enumerate(scope_2):
        test["run"] = index
        test["duration"] = random.randint(1, 10)
        print(f"Scope 2: Loop({index}): {scope_2}")

我有这个比较范围 1 和范围 2 的输出。我无法发现差异或理解第一个行为。

Scope_1: [{'id': 'ID-1', 'summary': 'Summary-1'}, {'id': 'ID-1', 'summary': 'Summary-1'}]
Scope_2: [{'id': 'ID-2', 'summary': 'Summary-2'}, {'id': 'ID-2', 'summary': 'Summary-2'}]
Scope 1: Loop(0): [{'id': 'ID-1', 'summary': 'Summary-1', 'run': 0, 'duration': 1}, {'id': 'ID-1', 'summary': 'Summary-1', 'run': 0, 'duration': 1}]
Scope 1: Loop(1): [{'id': 'ID-1', 'summary': 'Summary-1', 'run': 1, 'duration': 8}, {'id': 'ID-1', 'summary': 'Summary-1', 'run': 1, 'duration': 8}]
Scope 2: Loop(0): [{'id': 'ID-2', 'summary': 'Summary-2', 'run': 0, 'duration': 6}, {'id': 'ID-2', 'summary': 'Summary-2'}]
Scope 2: Loop(1): [{'id': 'ID-2', 'summary': 'Summary-2', 'run': 0, 'duration': 6}, {'id': 'ID-2', 'summary': 'Summary-2', 'run': 1, 'duration': 1}]

标签: python

解决方案


当您这样做时scope_1 = [test_object for _ in range(repeat)],您不会创建 test_object 的副本。您只是在列出对 test_object 的引用。这意味着两者都scope_1[0]指向scope_1[1]同一个字典。

要解决此问题,请在理解列表中创建字典的副本:

scope_1 = [test_object.copy() for _ in range(repeat)]

推荐阅读