【发布时间】:2019-04-15 16:12:49
【问题描述】:
在类定义期间,定义为字典的类变量用于构造第二个字典类变量,这是从第一个字典类变量缩减的子集,如下所示:
class C(object):
ALL_ITEMS = dict(a='A', b='B', c='C', d='D', e='E')
SUBSET_X = {k: v for k, v in ALL_ITEMS.items() if k in ('a', 'b', 'd')} # (this works)
SUBSET_Y = {k: ALL_ITEMS[k] for k in ('a', 'b', 'd')} # (this fails)
相当简单的东西,但执行此代码的最终效果让我感到非常惊讶。我的第一种方法是第 4 行的代码,但我不得不求助于第 3 行的解决方案。我显然无法掌握字典理解范围规则的一些微妙之处。
具体来说,在失败的情况下引发的错误是:
File "goofy.py", line 4, in <dictcomp>
SUBSET_Y = {k: ALL_ITEMS.get(k) for k in ('a', 'b', 'd')}
NameError: name 'ALL_ITEMS' is not defined
由于几个不同的原因,这个错误的性质让我感到困惑:
-
SUBSET_Y的赋值是一个格式良好的字典理解,并引用了一个应该在范围内且可访问的符号。 - 在随后的情况下(分配给
SUBSET_X),这也是一个字典理解,符号ALL_ITEMS是完美定义和可访问的。因此,在失败的情况下引发的异常是NameError的事实似乎显然是错误的。 (或者充其量是误导。) - 为什么
items()与__getitem__或get()的范围规则不同? (在失败的情况下,将ALL_ITEMS[k]替换为ALL_ITEMS.get(k)也会出现同样的异常。)
(即使作为 Python 开发人员十多年,我也从未遇到过这种失败,这要么意味着我很幸运,要么过着隐蔽的生活:^)
在各种 3.6.x CPython 版本以及 2.7.x 版本中都会出现同样的故障。
编辑:不,这不是上一个问题的重复。这与列表推导有关,即使要对字典推导进行相同的解释,也不能解释我引用的两种情况之间的区别。而且,这不仅仅是 Python 3 独有的现象。
【问题讨论】:
-
我在您的代码中的任何地方都看不到 ALL_KEYS。错误是否引用了 ALL_ITEMS?
标签: python class dictionary scoping