Python3.8 中的初始化扩展列表嵌套在字典中时从值类型切换到引用类型?

Initalizing extended list in Python3.8 switch from value-type to reference-type when nested in dicts?

Python Debian 上的 3.8.5

我发现了一个实例,其中更新字典项目列表中的单个元素实际上会更新子列表中的所有元素。这似乎是一个 reference/value 问题,但我不确定为什么这会在字典列表的情况下发生变化?

我了解用一定数量的元素初始化列表...

# Create list of 5 zeros 
ex_lst = [0] * 5
print(ex_lst) # [0, 0, 0, 0, 0]

# Update first index of list 
ex_lst[0] = 42
print(ex_lst) # [42, 0, 0, 0, 0]

在字典中做同样的事情

# Create dict containing list of 5 zeros 
ex_dict = {
    'ex_lst': [0]*5
}
print(ex_dict) # {'ex_lst': [0, 0, 0, 0, 0]}

# Update first index in list in dict
ex_dict['ex_lst'][0] = 42
print(ex_dict) # {'ex_lst': [42, 0, 0, 0, 0]}

但这就是奇怪的地方...

# Create dict containing child dict containing list of 5 zeros
ex_dict = {
    'chld_dict': [{
        'ex_lst': [0]
    }] * 5
}
print(ex_dict) # {'chld_dict': [{'ex_lst': [0]}, {'ex_lst': [0]}, {'ex_lst': [0]}, {'ex_lst': [0]}, {'ex_lst': [0]}]}

# Update first index of list in child dict in parent dict (updates all elements?)
ex_dict['chld_dict'][0]['ex_lst'][0] = 42
print(ex_dict) # {'chld_dict': [{'ex_lst': [42]}, {'ex_lst': [42]}, {'ex_lst': [42]}, {'ex_lst': [42]}, {'ex_lst': [42]}]}

当我只尝试更新第一个时,为什么列表中的所有元素都会更新?我明白 Python 并没有真正做到 by-object/by-value 因为“一切都是对象!”。但是我不明白为什么会这样。

我已经通过使用列表理解代替“*”运算符解决了这个问题,我只是想知道它背后是否有原因。谢谢!

Python 将 {'ex_lst': [0]} 解释为一个对象,因此当尝试创建 this 的五个元素时,它会创建五个引用同一对象的元素,这解释了这样的行为。 这也解释了为什么使用列表理解会起作用,因为每次使用列表理解时都会创建新对象。
正如@Matthew Cox 在评论中提到的,我们可以通过查看对象的 id 并验证它们是否相等来观察这一点:id(ex_dict['chld_dict'][0]) == id(ex_dict['chld_dict'][1]) which returns True.