gpt4 book ai didi

使用字典理解的 Python 类变量赋值

转载 作者:行者123 更新时间:2023-12-02 17:02:40 34 4
gpt4 key购买 nike

在类定义期间,定义为字典的类变量用于构造第二个字典类变量,这是第一个字典类变量的子集,如下所示:

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

由于几个不同的原因,这个错误的性质让我感到困惑:

  1. SUBSET_Y 的赋值是一个格式正确的字典理解,并引用一个应该在范围内且可访问的符号。
  2. 在后续情况(对 SUBSET_X 的赋值)中,这也是一个字典推导式,符号 ALL_ITEMS 是完美定义且可访问的。因此,在失败情况下引发的异常是 NameError 这一事实似乎显然是错误的。 (或者充其量是误导。)
  3. 为什么 items()__getitem__get() 的范围规则不同? (在失败情况下,将 ALL_ITEMS[k] 替换为 ALL_ITEMS.get(k) 会发生相同的异常。)

(即使作为一名 Python 开发人员已有十多年,我以前从未遇到过这种失败,这要么意味着我很幸运,要么过着被庇护的生活:^)

同样的故障发生在各种 3.6.x CPython 版本以及 2.7.x 版本中。

编辑:不,这不是上一个问题的重复。这与列表推导有关,即使将相同的解释转换到字典推导上,也无法解释我引用的两个案例之间的区别。而且,这不仅仅是 Python 3 的现象。

最佳答案

有一个小细节可以解释为什么第一个版本有效而​​第二个版本失败。第二个版本失败的原因与 this question 中给出的原因相同,也就是说,所有推导式构造(在 Python 3 中,在 Python 2 中,列表推导式的实现方式不同)创建一个函数作用域,所有本地名称绑定(bind)都发生在该作用域中。但是,类作用域中的名称对于类作用域内定义的函数是不可访问的。这就是为什么您必须使用 self.MY_CLASS_VARMyClass.MY_CLASS_VAR 从方法访问类变量的原因。

您的第一个案例确实有效的原因很微妙。根据language reference

The comprehension consists of a single expression followed by at least one for clause and zero or more for or if clauses. In this case, the elements of the new container are those that would be produced by considering each of the for or if clauses a block, nesting from left to right, and evaluating the expression to produce an element each time the innermost block is reached.

However, aside from the iterable expression in the leftmost for clause, the comprehension is executed in a separate implicitly nested scope. This ensures that names assigned to in the target list don’t “leak” into the enclosing scope.

The iterable expression in the leftmost for clause is evaluated directly in the enclosing scope and then passed as an argument to the implictly nested scope.

因此,在第一种情况下,ALL_ITEMS.items() 位于最左侧的 for 子句中,因此它直接在封闭范围内求值,在在本例中,类作用域,因此它很高兴地找到了 ALL_ITEMS 名称。

关于使用字典理解的 Python 类变量赋值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53270659/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com