Python 3 - 类变量未定义 [英] Python 3 - Class variable is not defined
问题描述
在这里我无法访问 Python 中的类变量列表理解.
Here I'm not able to access the class variable inside a Python's list comprehension.
class Student:
max_year = 18
year_choice = [i for i in range(100) if i > max_year]
def __init__(self, name):
self.name = name
print (self.year_choice)
Student('Blah')
但它在 Python 2 中运行良好.
But it's working fine in Python 2.
../workspace$ python student.py
[19, 20, 21, 22, 2.... 99]
但是在 Python 3 中出现错误.
But getting an error in Python 3.
../workspace$ python student.py
File "student.py", line 18, in <listcomp>
year_choice = [i for i in range(100) if i > max_year]
NameError: name 'max_year' is not defined
从调试这个当我改变以下声明
from debugging this When I changed below statement
[i for i in range(100) if i >max_year]
到这里
[i for i in range(max_year)] # don't look too much into it ;)
工作正常.为什么我无法访问 if/else 列表推导式中的类变量?
working fine. Why I'm not able to access class variable inside if/else list comprehension?
推荐答案
这行的原因
year_choice = [i for i in range(100) if i > max_year]
在 Python 2 中有效但在 Python 3 中无效是因为在 Python 3 列表推导式中创建了一个新的范围,而 max_year
类属性不在该范围内.在 Python 2 中,列表推导式不会创建新的作用域,而是在周围代码的上下文中运行.这样做最初是出于性能原因,但很多人发现它很混乱,因此在 Python 3 中进行了更改,将列表推导式与生成器表达式以及 set 和 dict 推导式保持一致.
works in Python 2 but not in Python 3 is that in Python 3 list comprehensions create a new scope, and the max_year
class attribute isn't in that scope. In Python 2, a list comprehension doesn't create a new scope, it runs in the context of the surrounding code. That was originally done for performance reasons, but a lot of people found it confusing, so it was changed in Python 3, bringing list comprehensions into line with generator expressions, and set and dict comprehensions.
AFAIK,在 Python 3 中没有简单的方法来访问在类的外部上下文中运行的列表推导中的类属性,而不是在方法内部.你不能用 Student.max_year
引用它,因为那时 Student
类不存在.
AFAIK, there is no simple way in Python 3 to access a class attribute inside a list comprehension that is running in the outer context of a class, rather than inside a method. You can't refer to it with Student.max_year
, since at that point the Student
class doesn't exist.
然而,无论如何,在那里进行列表理解确实没有意义.您可以更紧凑、更高效地创建您想要的列表.例如:
However, there really is no point having that list comprehension there anyway. You can create the list you want more compactly, and more efficiently. For example:
class Student(object):
max_year = 18
year_choice = list(range(max_year + 1, 100))
def __init__(self, name):
self.name = name
print (self.year_choice)
Student('Blah')
输出
[19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
该代码在 Python 2 和 Python 3 上产生相同的输出.
That code produces the same output on Python 2 and Python 3.
我已将类签名更改为
class Student(object):
以便它在 Python 2 中创建一个新样式的类(在 Python 3 中所有类都是新样式).
so that it creates a new-style class in Python 2 (in Python 3 all classes are new-style).
[i for i in range(max_year)]
可以绕过这个限制的原因是从 range(max_year)
创建了一个迭代器,然后通过作为运行列表理解的临时函数的参数.所以它等价于这段代码:
The reason that [i for i in range(max_year)]
can get around this restriction is that an iterator is created from range(max_year)
which is then passed as the argument to the temporary function which runs the list comprehension. So it's equivalent to this code:
class Student(object):
max_year = 18
def _listcomp(iterator):
result = []
for i in iterator:
result.append(i)
return result
year_choice = _listcomp(iter(range(max_year + 1, 100)))
del _listcomp
def __init__(self, name):
self.name = name
print(self.year_choice)
Student('Blah')
非常感谢 Antti Haapala 的解释.
Many thanks to Antti Haapala for this explanation.
这篇关于Python 3 - 类变量未定义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!