为什么a = a ['k'] = {}创建一个无限嵌套的字典?

Sus*_*Pal 8 python dictionary reference operator-precedence assignment-operator

这是我的Python代码,它创建了一个无限嵌套的字典:

a = a['k'] = {}

print(a)
print(a['k'])
print(a['k']['k'])
print(a is a['k'])
Run Code Online (Sandbox Code Playgroud)

这是输出:

{'k': {...}}
{'k': {...}}
{'k': {...}}
True
Run Code Online (Sandbox Code Playgroud)

输出显示a['k']引用a自身,使其无限嵌套.

我猜这句话:

a = a['k'] = {}
Run Code Online (Sandbox Code Playgroud)

表现得像:

new = {}
a = new
a['k'] = new
Run Code Online (Sandbox Code Playgroud)

这确实会创建一个无限嵌套的字典.

我查看了第7.2节:Python语言参考的赋值语句,但我找不到任何暗示a = a['k'] = {}应首先设置a为新字典然后在该字典中插入键/值对的内容.以下是我发现相关但没有回答我的问题的参考摘录:

如果目标列表是没有尾随逗号的单个目标,可选择在括号中,则将该对象分配给该目标.

如果目标是订阅:将评估引用中的主表达式.它应该产生可变序列对象(例如列表)或映射对象(例如字典).接下来,评估下标表达式.

如果primary是映射对象(例如字典),则下标必须具有与映射的键类型兼容的类型,然后要求映射创建将下标映射到指定对象的键/数据对.这可以用相同的键值替换现有的键/值对,或者插入新的键/值对(如果不存在具有相同值的键).

这些摘录中的每一个都定义了具有单个目标的任务的行为,例如a = {},a['k'] = {}但是他们似乎并没有谈论在情况下会发生什么a = a['k'] = {}.记录此类声明的评估顺序在哪里?

GPh*_*ilo 5

根据您引用的第 7.2 节(强调我的),赋值语句中的赋值从左到右解析:

赋值语句评估表达式列表(请记住,这可以是单个表达式或逗号分隔的列表,后者产生一个元组)并将单个结果对象从左到右分配给每个目标列表。

这意味着是的,您的陈述确实相当于:

new = {}
a = new
a['k'] = new
Run Code Online (Sandbox Code Playgroud)

作为快速反证,交换分配顺序会导致错误:

a['k'] = a = {}
Run Code Online (Sandbox Code Playgroud)

加注

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你。这是有道理的。赋值语句定义为`assignment_stmt ::= (target_list "=")+ (starred_expression | yield_expression)`,所以`a = a['k'] = {}`有两个`target_list`元素(`a`和` a['k']`) 和一个 `starred_expression` 元素(`{}`),因此从左到右将 `{}` 分配给每个目标列表 `a` 和 `a['k']` . (2认同)