我想做:
class Whatevs(object):
foo = 3
bar = foo * 3
def __init__(self):
# enhance!
或如何使我能够正常工作。 ;)
修改
好的,事实证明这不是问题,上面的工作正常,这个虽然:
class Whatevs(object):
foo = 3
zap = list(foo for _ in range(10))
哦,你,Python!我可以提出一些解决方法,但有人可以向我解释一下究竟发生了什么吗?为什么生成器不能访问类变量?
答案 0 :(得分:4)
生成器理解实际上是显式定义生成器的简写。在幕后你想写的东西相当于:
class Whatevs(object):
foo = 3
def _gen():
for _ in range(10):
yield foo
zap = list(_gen())
不幸的是,您无法从生成器内部或类体中定义的函数中访问范围变量(如foo
)(并且您无法使用Whatevs.foo
,因为Whatevs
尚不存在
一种选择是将代码移到类体外:
class Whatevs(object):
foo = 3
Whatevs.zap = list(Whatevs.foo for _ in range(10))
另一种选择是将foo变成参数:
def _init_zap(foo):
return list(foo for _ in range(10))
class Whatevs(object):
foo = 3
zaps = _init_zap(foo)
在Python 2.xa中,列表理解在这里起作用,但是Python 3.x的一个变化是列表推导也使用单独的作用域(即隐藏函数),就像生成器理解一样,因此列表理解也会破坏在Python 3中。
答案 1 :(得分:1)
你可以尝试:
class Whatevs(object):
foo = 3
zap = [foo] * 10
甚至:
class Whatevs(object):
foo = 3
zap = [foo for _ in range(10)]
原因是Python中的类有自己的命名空间。引入此命名空间的作用域无法访问此命名空间,因此,从生成器表达式的范围,您无法访问Whatevs
'命名空间内的变量。
我的列表理解并没有引入新的范围 - 至少在Python 2.x中。在Python 3.x中,这已经改变了,所以我的选项2也不起作用。
答案 2 :(得分:1)
一般的解决方案是包装lambda函数,在Python2和Python3中以相同的方式工作
class Whatevs(object):
foo = 3
zap = (lambda foo=foo:list(foo for _ in range(10)))()