【发布时间】:2019-07-15 10:43:21
【问题描述】:
这是我创建无限嵌套字典的 Python 代码:
a = a['k'] = {}
print(a)
print(a['k'])
print(a['k']['k'])
print(a is a['k'])
这是输出:
{'k': {...}}
{'k': {...}}
{'k': {...}}
True
输出显示a['k'] 引用a 本身,这使其无限嵌套。
我猜是这样的说法:
a = a['k'] = {}
行为如下:
new = {}
a = new
a['k'] = new
这确实会创建一个无限嵌套的字典。
我查看了Python 语言参考的Section 7.2: Assignment statements,但我找不到任何暗示a = a['k'] = {} 应该首先将a 设置为新字典然后 在该字典中插入一个键/值对。以下是我认为相关但没有回答我的问题的参考摘录:
如果目标列表是一个没有尾随逗号的目标,可选在括号中,则将对象分配给该目标。
如果目标是订阅:计算引用中的主要表达式。它应该产生一个可变序列对象(例如列表)或映射对象(例如字典)。接下来,计算下标表达式。
如果主要是映射对象(例如字典),则下标必须具有与映射的键类型兼容的类型,然后要求映射创建一个键/数据对,将下标映射到分配的目的。这可以用相同的键值替换现有的键/值对,或者插入一个新的键/值对(如果不存在具有相同值的键)。
这些摘录中的每一个都定义了具有单个目标的赋值行为,例如 a = {} 和 a['k'] = {},但它们似乎没有讨论在 a = a['k'] = {} 的情况下应该发生什么。此类声明的评估顺序记录在哪里?
这个问题现在已经解决了。 GPhilo的回答指向了Section 7.2: Assignment statements的相关条款。相关条款一开始是对的,但我之前忽略了它。这里是:
赋值语句计算表达式列表(请记住,这可以是单个表达式或逗号分隔的列表,后者产生一个元组)并将单个结果对象从左到右分配给每个目标列表。
现在让我们将它与语法进行比较。
赋值语句定义为
assignment_stmt ::= (target_list "=")+ (starred_expression | yield_expression)
所以声明
a = a['k'] = {}
有两个target_list元素,即a和a['k'],还有一个starred_expression元素,即{},所以{}被分配给每个目标列表a和@ 987654344@从左到右。
【问题讨论】:
标签: python dictionary reference assignment-operator operator-precedence