【发布时间】:2020-01-02 05:58:30
【问题描述】:
在将代码从 Py2 升级到 Py3 时,我遇到了一个我无法解释的奇怪现象。类定义中的列表推导可以引用 python 2 和 3 中的其他类级别变量作为for 子句的一部分。但是,如果变量是 if 子句的一部分,它们会在 python 3 中抛出 NameError,但在 python 2 中可以正常工作。
我发现了一些相关的问题,但它们似乎并不能完全解释这个问题。 Dictionary class attribute that refers to other class attributes in the definition 是 lambdas 中的一个类似问题,但似乎与 python 版本无关。另外Why am I getting a NameError in list comprehension (Python)?,但与调试器中的作用域而不是类有关。
以下代码在 python 2.7.16 上运行良好,但在 Python 3.7.4 上失败:
class A(object):
a = [1, 2, 3]
b = [n for n in a if n in a]
print(A.b)
在 python 2 中我得到:
[1, 2, 3]
在 python 3 中我得到:
Traceback (most recent call last):
File "list_comprehension_closure.py", line 3, in <module>
class A(object):
File "list_comprehension_closure.py", line 5, in A
b = [n for n in a if n in a]
File "list_comprehension_closure.py", line 5, in <listcomp>
b = [n for n in a if n in a]
NameError: name 'a' is not defined
但是,以下在 python 2 和 3 中都可以正常工作,唯一的区别是 if 子句:
class A(object):
a = [1, 2, 3]
b = [n for n in a]
print(A.b)
此外,以下代码在 python 2 和 3 中都有效,唯一的区别是理解是在 class 块之外定义的:
a = [1, 2, 3]
b = [n for n in a if n in a]
print(b)
我知道 Python 3 中的闭包和列表解析发生了一些变化,但我没有看到任何可以解释这种差异的东西。
编辑: 为清楚起见,我不是在寻找解决方法。正如我上一个示例所展示的,我知道将变量移到类范围之外可以解决问题。但是,我正在寻找的是解释为什么在 python 3 中这种行为发生了变化。
【问题讨论】:
-
将python 2代码复制到你的python 3文件并再次运行
-
@U10-Forward 虽然在发布后的 10 分钟内发现任一版本的 python 都发生了重大变化,这让我感到惊讶,但为了成为一项好运动,我在 python 中运行了相同的代码2 和 3 再次得到相同的结果:``` > cat list_comprehension_closure.py class A(object): a = [1, 2, 3] b = [n for n in a if n in a] print(Ab) > python2.7 list_comprehension_closure.py [1, 2, 3] > python3.7 list_comprehension_closure.py ... NameError: name 'a' is not defined ```
-
@hunzter 谢谢,我在搜索中没有看到这个问题。但是,它并不能完全解决问题。关于为什么我在 if 子句中引用
a的第一个示例失败的解释是有道理的。我可能在字节码分解中遗漏了一些东西,但我对此的阅读似乎表明我的第二个示例a仅在 python 3 中的for子句 should fail 中引用,但是它没有。 -
@hunzter,实际上经过仔细阅读,链接的问题确实解决了我的第二个示例为何有效。 “无论 Python 版本如何,理解或生成器表达式的一部分都在周围范围内执行。那将是最外层可迭代的表达式。”
标签: python python-3.x