我认为我知道变量和生成器在Python中是如何工作的 但是,以下代码让我感到困惑。
from __future__ import print_function
class A(object):
x = 4
gen = (x for _ in range(3))
a = A()
print(list(a.gen))
运行代码(Python 2)时,它说:
Traceback (most recent call last): File "Untitled 8.py", line 10, in <module> print(list(a.gen)) File "Untitled 8.py", line 6, in <genexpr> gen = (x for _ in range(3)) NameError: global name 'x' is not defined
在Python 3中,它说NameError: name 'x' is not defined
但是,当我跑步时:
from __future__ import print_function
class A(object):
x = 4
lst = [x for _ in range(3)]
a = A()
print(a.lst)
代码在Python 3中不起作用,但它在Python 2中或在像这样的函数中起作用
from __future__ import print_function
def func():
x = 4
gen = (x for _ in range(3))
return gen
print(list(func()))
此代码适用于Python 2和Python 3或模块级
from __future__ import print_function
x = 4
gen = (x for _ in range(3))
print(list(gen))
该代码也适用于Python 2和Python 3。
class
为何错误?
答案 0 :(得分:6)
因为x
是一个类属性(静态变量),您可以访问它,
示例强>
>>> class A(object):
... x = 4
... gen = (A.x for _ in range(3))
...
>>> a = A()
>>> list(a.gen)
[4, 4, 4]
这里甚至gen
是另一个类属性,这意味着,
>>> b = A()
>>> list(b.gen)
[]
这是空的,因为发电机已经耗尽。
<小时/> 发生这种情况是因为只有在您发出
a.gen
时才会评估生成器,因为它无法解析名称x
。
答案 1 :(得分:5)
正如其他答案中所述,它发生的是True
,因为它是静态变量。但是,限制代码工作的不仅仅是那个属性。实际原因是变量的范围及其执行的范围。例如,创建一个类:
class A(object):
x = 999999
y = x +1
如果您访问它的类属性A.x
和A.y
,它将起作用。因为,在初始化y
时,x
会替换为表达式x+1
中的值。由于x
的范围属于班级。
然而,在发电机的情况下不会发生这种情况。即在你的例子中:
class A(object):
x = 4
gen = (x for _ in range(3))
执行list(a.gen)
时,它在类外执行(因为在运行时评估生成器)并检查当前作用域中x
的引用。由于x
未在该范围内初始化,因此会引发错误。
当您显式初始化x=4
时,它可以正常工作,因为现在生成器表达式的值可以使用x
。
为了使您的生成器表达式工作,如其他人所述,您必须将其定义为:
class A(object):
x = 4
gen = (A.x for _ in range(3))
# ^ mentioning `A.x` is the value to access
答案 2 :(得分:1)
这是因为x
是一个类变量。在python中,必须使用self
(例如,从实例方法访问)或类名访问类变量。
class A(object):
x = 4
gen = (A.x for _ in range(3))
def call_me(self):
print self.x
a = A()
a.call_me()
print list(a.gen)
有关详细讨论,请参阅 Static class variables in Python 和 Why is Python class not recognizing static variable