在类定义中执行语句:解释器知道哪些变量?

2024-10-05 14:27:50 发布

您现在位置:Python中文网/ 问答频道 /正文

下面是我的部分类定义:

class Trial:
    font = pygame.font.Font(None, font_size)
    target_dic = {let: font.render(let, True, WHITE, BG) for let in list("ABCDEFGHJKLMNPRSTUVWX")}

分部类定义的最后一行,target_dic = {let: font.render(let, True, WHITE, BG) for let in list("ABCDEFGHJKLMNPRSTUVWX")返回错误:未定义全局名称“font”。很公平。在

但是,我尝试了以下测试用例,没有错误:

^{pr2}$

为什么第一个案子不起作用?在达到字典理解时,成员font不存在吗?在

我需要将这些操作移动到__init__还是可以在创建类对象时只定义一次列表?在

编辑:

为了清楚起见,我希望能够在类对象创建时填充列表,以减少创建试用对象所花费的时间。在


Tags: 对象intruetargetfor定义错误render
3条回答

在类创建过程中可用的名称是全局变量,并且名称已经在类的顶层定义(也就是说,随着名称的定义,它们在类代码的后面变得可用)。在

请注意,类级别的对象可能不是通过实例获得的,甚至不是通过类对象获得的;最明显的是,在类创建过程中,def的结果仍然是函数而不是方法。在

关于OP的代码,这个例子显示了font是在类级别定义的:

class Trial:
    font = 'foo'
    target_dic = dict((lambda fnt:((let,fnt) for let in "ABCDEFGHJKLMNPRSTUVWX"))(font))
    target_two = []
    for let in "ABCDEFGHJKLMNPRSTUVWX":
        target_two.append(let)

print(Trial.target_dic)
print(Trial.target_two)

这就产生了:

^{pr2}$

在(http://ideone.com/aC7VY)在

font可按预期传递给lambda。在

问题在于类作用域中没有可用的名称(font在那里可用)。问题是理解引入了一个新的范围(在python3中):http://docs.python.org/py3k/reference/expressions.html#displays-for-lists-sets-and-dictionaries

因为类decorator是在类创建之后调用的,所以可以使用它来解决在类主体中引用类属性的限制,并有效地“后处理”刚刚创建的类并添加任何缺少的属性:

def trial_deco(cls):
    cls.target_dic = {let: cls.font.render(let, True, WHITE, BG) for let in "ABCDEFGHJKLMNPRSTUVWXZ"}
    return cls

@trial_deco
class Trial:
    font = pygame.font.Font(None, font_size)
    target_dic = None  # redefined by decorator

另一种方法是使属性最初成为一个数据描述符(也称为“属性”),该描述符(仅)在第一次读取属性时被调用。这是通过用计算出的值覆盖描述符来完成的,因此它只发生一次。在

^{pr2}$

也有其他的方法来做这类事情,比如使用元类或者定义一个__new__方法,但是令人怀疑的是,任何一种方法都能更好地工作,或者不那么复杂。在

部分回答,因为这更多的是切断一些错误的道路。在

如果我把你的工作样本拿回来,做一个口述理解:

class x:
    dat = 1
    datlist = {i:dat for i in range(10)}

我也知道:

^{pr2}$

所以看起来dict comprehension隐藏了类语句执行期间dict的临时dict使用,但是list comprehension没有

到目前为止,在文档中找不到关于这个的更多信息。。。在

根据@interjay评论编辑: 不满足作用域规范的类构造在post中进行了处理。简而言之,在2.x中,列表理解是有缺陷的,并且可以看到类成员,但他们不应该这样做

相关问题 更多 >