如何从类定义中的列表理解中访问其他类变量?以下代码在python2中有效,但在python3中无效:
class Foo:
x = 5
y = [x for i in range(1)]
Python 3.2给出了以下错误:
NameError: global name 'x' is not defined
尝试Foo。X也不行。关于如何在python3中做到这一点,有什么想法吗?
一个稍微复杂一点的激励例子:
from collections import namedtuple
class StateDatabase:
State = namedtuple('State', ['name', 'capital'])
db = [State(*args) for args in [
['Alabama', 'Montgomery'],
['Alaska', 'Juneau'],
# ...
]]
在这个例子中,apply()本来是一个不错的解决方案,但不幸的是,它从Python 3中被删除了。
公认的答案提供了很好的信息,但这里似乎还有一些其他问题——列表理解和生成器表达式之间的差异。我玩了一个演示:
class Foo:
# A class-level variable.
X = 10
# I can use that variable to define another class-level variable.
Y = sum((X, X))
# Works in Python 2, but not 3.
# In Python 3, list comprehensions were given their own scope.
try:
Z1 = sum([X for _ in range(3)])
except NameError:
Z1 = None
# Fails in both.
# Apparently, generator expressions (that's what the entire argument
# to sum() is) did have their own scope even in Python 2.
try:
Z2 = sum(X for _ in range(3))
except NameError:
Z2 = None
# Workaround: put the computation in lambda or def.
compute_z3 = lambda val: sum(val for _ in range(3))
# Then use that function.
Z3 = compute_z3(X)
# Also worth noting: here I can refer to XS in the for-part of the
# generator expression (Z4 works), but I cannot refer to XS in the
# inner-part of the generator expression (Z5 fails).
XS = [15, 15, 15, 15]
Z4 = sum(val for val in XS)
try:
Z5 = sum(XS[i] for i in range(len(XS)))
except NameError:
Z5 = None
print(Foo.Z1, Foo.Z2, Foo.Z3, Foo.Z4, Foo.Z5)
由于最外层的迭代器是在周围范围内计算的,我们可以将zip与itertools一起使用。重复将依赖项转移到理解范围:
import itertools as it
class Foo:
x = 5
y = [j for i, j in zip(range(3), it.repeat(x))]
还可以在推导式中使用嵌套for循环,并在最外层的可迭代对象中包含依赖项:
class Foo:
x = 5
y = [j for j in (x,) for i in range(3)]
对于OP的具体例子:
from collections import namedtuple
import itertools as it
class StateDatabase:
State = namedtuple('State', ['name', 'capital'])
db = [State(*args) for State, args in zip(it.repeat(State), [
['Alabama', 'Montgomery'],
['Alaska', 'Juneau'],
# ...
])]