类中生成器的变量范围

Wei*_*gTu 11 python variables generator

我想我知道变量和生成器在Python中是如何工作的.
但是,以下代码让我感到困惑.

from __future__ import print_function

class A(object):
    x = 4
    gen = (x for _ in range(3))

a = A()
print(list(a.gen))
Run Code Online (Sandbox Code Playgroud)

运行代码(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
Run Code Online (Sandbox Code Playgroud)

在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)
Run Code Online (Sandbox Code Playgroud)

该代码在Python 3中不起作用,但它在Python 2中或在像这样的函数中起作用

from __future__ import print_function

def func():
    x = 4
    gen = (x for _ in range(3))
    return gen

print(list(func()))
Run Code Online (Sandbox Code Playgroud)

此代码适用于Python 2和Python 3或模块级别

from __future__ import print_function

x = 4
gen = (x for _ in range(3))

print(list(gen))
Run Code Online (Sandbox Code Playgroud)

该代码也适用于Python 2和Python 3.

为什么错了class

nu1*_*73R 6

因为x是一个类属性(静态变量),你可以访问,

>>> class A(object):
...     x = 4
...     gen = (A.x for _ in range(3))
...
>>> a = A()
>>> list(a.gen)
[4, 4, 4]
Run Code Online (Sandbox Code Playgroud)

这里甚至gen是另一个类属性,这意味着,

>>> b = A()
>>> list(b.gen)
[]
Run Code Online (Sandbox Code Playgroud)

这是空的,因为发电机已经耗尽.


发生这种情况是因为只有在发出a.gen时才会评估生成器,而无法解析名称x.

  • @MoinuddinQuadri使用`y = x + 1`,当处理`class`语句的主体时,如果设置了`y`的值,则立即查找`x`的值*.`(x for _ in range(3))`创建一个生成器表达式,在实际尝试使用生成的生成器中的值之前,不会对其进行求值.也就是说,查找"x"发生在`class`语句之外. (2认同)

Moi*_*dri 5

正如其他答案所述,True它发生的原因是它是静态变量.但是,限制代码工作的不仅仅是那个属性.实际原因是变量的范围及其执行的范围.例如,创建一个类:

class A(object):
    x = 999999
    y = x +1
Run Code Online (Sandbox Code Playgroud)

如果你访问它的类属性A.xA.y,它会工作.因为,在初始化时y,x将替换表达式中的值x+1.由于范围x是在班级内.

然而,在发电机的情况下不会发生这种情况.即在你的例子中:

class A(object):
    x = 4
    gen = (x for _ in range(3))
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)