类属性评估和生成器 [英] Class attribute evaluation and generators

查看:166
本文介绍了类属性评估和生成器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Python如何评估类属性?我遇到了一个有趣的怪癖(在Python 2.5.2),我想解释。

How exactly does Python evaluate class attributes? I've stumbled across an interesting quirk (in Python 2.5.2) that I'd like explained.

我有一个类有一些属性定义其他,以前定义的属性。当我尝试使用一个生成器对象时,Python会抛出一个错误,但是如果我使用一个普通的列表解析,没有问题。

I have a class with some attributes that are defined in terms of other, previously defined attributes. When I try using a generator object, Python throws an error, but if I use a plain ordinary list comprehension, there's no problem.

这里是一个简单的例子。注意,唯一的区别是 Brie 使用生成器表达式,而 Cheddar 使用列表解析。

Here's the pared-down example. Note that the only difference is that Brie uses a generator expression, while Cheddar uses a list comprehension.

# Using a generator expression as the argument to list() fails
>>> class Brie :
...     base = 2
...     powers = list(base**i for i in xrange(5))
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in Brie
  File "<stdin>", line 3, in <genexpr>
NameError: global name 'base' is not defined

# Using a list comprehension works
>>> class Cheddar :
...     base = 2
...     powers = [base**i for i in xrange(5)]
... 
>>> Cheddar.powers
[1, 2, 4, 8, 16]

# Using a list comprehension as the argument to list() works
>>> class Edam :
...     base = 2
...     powers = list([base**i for i in xrange(5)])
...
>>> Edam.powers
[1, 2, 4, 8, 16]

case是更复杂的,我创建一个dict,但这是我可以找到的最小示例。)

(My actual case was more complicated, and I was creating a dict, but this is the minimum example I could find.)

我唯一的猜想是列表推导是在线,但是生成器表达式在类的结束之后计算,在该点范围已更改。但我不知道为什么生成器表达式不作为一个闭包,并存储对基线的范围在行的引用。

My only guess is that the list comprehensions are computed at that line, but the generator expressions are computed after the end of the class, at which point the scope has changed. But I'm not sure why the generator expression doesn't act as a closure and store the reference to base in the scope at the line.

有理由如果是这样,我应该如何考虑类属性的评估机制?

Is there a reason for this, and if so, how should I be thinking of the evaluation mechanics of class attributes?

推荐答案

, 这个。一个类没有真正引入一个新的范围,它只是有点像它的样子;这样的结构暴露了差异。

Yeah, it's a bit dodgy, this. A class doesn't really introduce a new scope, it just sort of looks a little bit like it does; constructs like this expose the difference.

这个想法是,当你使用一个生成器表达式时,它等同于使用一个lambda:

The idea is that when you're using a generator expression it's equivalent to doing it with a lambda:

class Brie(object):
    base= 2
    powers= map(lambda i: base**i, xrange(5))

或显式地作为函数语句:

or explicitly as a function statement:

class Brie(object):
    base= 2

    def __generatePowers():
        for i in xrange(5):
            yield base**i

    powers= list(__generatePowers())

在这种情况下,很明显 base 不在 __ generatePowers 一个异常结果(除非你是不幸的,也有一个 base 全局,在这种情况下你会错了)。

In this case it's clear that base isn't in scope for __generatePowers; an exception results for both (unless you were unlucky enough to also have a base global, in which case you get a wrongness).

这不会发生在列表推导,由于一些内部细节如何评估,但是这种行为在Python 3中将消失,这将在两种情况下同样失败。 这里有一些讨论。

This doesn't happen for list comprehensions due to some internal details on how they're evaluated, however that behaviour goes away in Python 3 which will fail equally for both cases. Some discussion here.

一个解决方法是使用一个lambda,使用我们在nested_scopes之前的坏日子依赖的相同的技术:

A workaround can be had using a lambda with the same technique we relied on back in the bad old days before nested_scopes:

class Brie(object):
    base= 2
    powers= map(lambda i, base= base: base**i, xrange(5))

这篇关于类属性评估和生成器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆