我目前正在将 codebase
从 python2 切换到 python3,遇到一个我不太明白的问题:
class MyClass:
var1 = True
var2 = tuple([i for i in [1, 2,] if var1])
上面的类在 python2 中运行得相当愉快,但在 python3 中就崩溃了。
我把它改成:
class MyClass:
var1 = True
var2 = tuple(i for i in [1, 2,] if var1)
因为我的理解是列表理解是多余的,不管它是否有效。经过一些调查后,似乎 list/tuple
理解的行为方式我不太理解它们何时在正在初始化的类的主体中。
# Breaks in python 2 and 3
class MyClass:
var1 = True
var2 = tuple(i for i in [1, 2,] if var1)
# Works in python 2, breaks in 3
class MyClass:
var1 = True
var2 = [i for i in [1, 2,] if var1]
关于发生了什么的任何指示?
关于第一种情况,您所拥有的实际上是将生成器表达式传递给甚至不是类属性的 tuple
函数。它实际上类似于下面的代码:
>>> class MyClass:
... var1 = True
... def func():
... return var1
... func()
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in MyClass
File "<stdin>", line 4, in func
NameError: global name 'var1' is not defined
正如您再次看到的那样,在 Python-2.7 和 3.X 中引发了 NameError
。原因是函数有自己的命名空间,并且没有特别声明该变量的状态(全局、局部、非局部)或通过类的实例访问 (self.var1
) 函数不会可以访问外部有界命名空间。
另一方面,列表推导式在 python-2 中可以访问定义它们的对象的命名空间。它们不像函数,没有函数所具有的许多特性。这实际上是一种双向关系。这就是说,虽然您可以在列表推导内使用变量,但您在列表推导内定义的内容也可以在其外部访问。并且由于人们倾向于在列表理解中使用一次性变量,这将导致您的代码出现变量泄漏。但是由于 Python-3.x 列表理解从函数中借用了私有(private)命名空间,因此它们可以拥有自己的命名空间。