提问人:Susam Pal 提问时间:2/21/2019 最后编辑:Susam Pal 更新时间:11/13/2021 访问量:2523
为什么 a = a['k'] = {} 会创建一个无限嵌套的字典?
Why does a = a['k'] = {} create an infinitely nested dictionary?
问:
这是我的 Python 代码,它创建了一个无限嵌套的字典:
a = a['k'] = {}
print(a)
print(a['k'])
print(a['k']['k'])
print(a is a['k'])
输出如下:
{'k': {...}}
{'k': {...}}
{'k': {...}}
True
输出显示 that 引用自身,使其无限嵌套。a['k']
a
我猜这句话:
a = a['k'] = {}
行为如下:
new = {}
a = new
a['k'] = new
这确实会创建一个无限嵌套的字典。
我查看了 Python 语言参考的第 7.2 节:赋值语句,但我找不到任何暗示应该首先设置为新字典,然后在该字典中插入键/值对的内容。以下是我认为相关但没有回答我的问题的参考资料的一些摘录:a = a['k'] = {}
a
如果目标列表是没有尾随逗号的单个目标(可选)在括号中,则将对象分配给该目标。
如果目标是订阅:将计算引用中的主要表达式。它应该生成一个可变序列对象(如列表)或一个映射对象(如字典)。接下来,计算下标表达式。
如果主对象是映射对象(如字典),则下标必须具有与映射的键类型兼容的类型,然后要求映射创建将下标映射到指定对象的键/基准对。这可以将现有的键/值对替换为相同的键值,也可以插入新的键/值对(如果不存在具有相同值的键)。
这些摘录中的每一个都定义了具有单个目标(例如 和 )的作业的行为,但它们似乎没有讨论在 .这种陈述的评估顺序记录在哪里?a = {}
a['k'] = {}
a = a['k'] = {}
这个问题现在已经解决了。GPhilo的回答指出了第7.2节的相关条款:转让语句。相关条款一开始就是对的,但我之前忽略了它。在这里:
赋值语句计算表达式列表(请记住,它可以是单个表达式或逗号分隔的列表,后者生成一个元组),并将单个生成的对象从左到右分配给每个目标列表。
现在让我们将其与语法进行比较。
赋值语句定义为
assignment_stmt ::= (target_list "=")+ (starred_expression | yield_expression)
所以声明
a = a['k'] = {}
有两个元素,即 和 ,以及一个元素,即 ,因此从左到右分配给每个目标列表。target_list
a
a['k']
starred_expression
{}
{}
a
a['k']
答:
根据您引用的第 7.2 节(强调我的),分配语句中的分配是从左到右解决的:
赋值语句计算表达式列表(请记住 这可以是单个表达式,也可以是逗号分隔的列表,后者 生成一个元组),并将单个结果对象分配给每个 目标列表,从左到右。
这意味着是的,实际上您的陈述等同于:
new = {}
a = new
a['k'] = new
作为快速的反证,交换分配的顺序会导致错误:
a['k'] = a = {}
提高
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
评论
assignment_stmt ::= (target_list "=")+ (starred_expression | yield_expression)
a = a['k'] = {}
target_list
a
a['k']
starred_expression
{}
{}
a
a['k']
{'k': {}}
a['k']
{}
{}
1
a == {}
a['k']
a['k']=={}
a is a['k']
评论