具有列表推导的类变量的范围

Mar*_*rte 5 python scope list-comprehension

看看下面这段代码:

class a:
    s = 'python'
    b = ['p', 'y']
    c = [x for x in s]
Run Code Online (Sandbox Code Playgroud)

输出:

>>> a.c
['p', 'y', 't', 'h', 'o', 'n']
Run Code Online (Sandbox Code Playgroud)

但当我试图限制列表时,如果:

class a:
    s = 'python'
    b = ['p', 'y']
    c = [x for x in s if x in b]
Run Code Online (Sandbox Code Playgroud)

显示以下异常:

Traceback (most recent call last):
  File "<pyshell#22>", line 1, in <module>
    class a:
  File "<pyshell#22>", line 4, in a
    c = [x for x in s if x in b]
  File "<pyshell#22>", line 4, in <listcomp>
    c = [x for x in s if x in b]
NameError: global name 'b' is not defined
Run Code Online (Sandbox Code Playgroud)

如果global b它有效,为什么会这样?

Two*_*ist 6

这与列表理解中的变量范围不同,关于类的工作方式.在Python 3中(但不是在Python 2中),列表推导不会影响它们的范围:

>>> [i for i in range(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> i
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'i' is not defined
>>> i = 0
>>> [i for i in range(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> i
0
Run Code Online (Sandbox Code Playgroud)

但是,当您在类中执行此操作时,它将不会像b在模块或函数的本地范围中那样在类属性中查找.要做你想做的事,请使用@property装饰器:

>>> class a:
...   s = 'python'
...   b = 'py'
...   @property
...   def c(self):
...     return [x for x in self.s if x in self.b]
... 
>>> A = a()
>>> A.c
['p', 'y']
Run Code Online (Sandbox Code Playgroud)

另外,请记住字符串也是可迭代的(它们只是组件字符的列表),因此无需显式创建b列表.