4

我想做:

class Whatevs(object):
    foo = 3
    bar = foo * 3

    def __init__(self):
        # enhance!

或我如何才能使其正常工作。;)

编辑:

好的,事实证明这不是问题,上面的工作正常,但是

class Whatevs(object):
    foo = 3
    zap = list(foo for _ in range(10))

哦,你,蟒蛇!我可以想出一些解决方法,但是有人可以向我解释到底发生了什么吗?为什么生成器不能访问类变量?

4

3 回答 3

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.x 中,列表推导在这里有效,但 Python 3.x 的变化之一是列表推导也使用单独的范围(即隐藏函数),就像生成器推导一样,因此列表推导在 Python 3 中也会中断.

于 2013-02-13T15:04:39.760 回答
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 也不起作用。

于 2013-02-13T14:51:51.753 回答
1

一个通用的解决方案是包装一个 lambda 函数,在 Python2 和 Python3 中的工作方式相同

class Whatevs(object):
    foo = 3
    zap = (lambda foo=foo:list(foo for _ in range(10)))()
于 2013-04-18T03:50:55.087 回答