python - 遍历列表上的字典更新所有元素而不是当前元素
问题描述
我正在通过列表理解生成一个字典列表,该列表理解只是根据输入参数重复元素 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}]
解决方案
当您这样做时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)]