在定义现有类变量时如何引用它们

时间:2013-02-13 14:48:16

标签: python

我想做:

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!我可以提出一些解决方法,但有人可以向我解释一下究竟发生了什么吗?为什么生成器不能访问类变量?

3 个答案:

答案 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)))()
相关问题