以下是我的部分类定义:
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'。很公平。
但是,我尝试了以下测试用例并没有出错:
class x:
dat = 1
datlist = [dat for i in range(10)]
为什么第一种情况不起作用?到达词典理解时,成员font
是否存在?
我是否需要将这些操作移至__init__
,或者在创建类对象时是否可以准确定义一次列表?
编辑:
为清楚起见,我希望能够在类对象创建时填充列表,以减少创建试验对象所花费的时间。
答案 0 :(得分:4)
部分答案,因为更多的是要削减一些错误的路径。
如果我收回你的工作样本并提出理解:
class x:
dat = 1
datlist = {i:dat for i in range(10)}
我也得到了这个:
>>> NameError: global name 'dat' is not defined
所以看起来dict理解是在类语句执行期间隐藏临时 dict ,但列表理解却没有。
目前在关于此的文档中找不到进一步的信息...
根据@interjay评论编辑: 在post中解决了不符合范围规范的阶级结构。简短的故事是,列表理解在2.x中是错误的并且看到了班级成员,但他们不应该。
答案 1 :(得分:1)
因为在创建类之后调用类装饰器,所以可以使用一个来解决在类体中引用类属性的限制,并有效地“后处理”刚创建的类并添加任何缺少的属性:
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
另一种方法是使属性最初成为数据描述符(也称为“属性”),该属性在第一次读取属性时被(仅)调用。这是通过用计算值覆盖描述符来实现的,所以它只发生一次。
class AutoAttr(object):
""" data descriptor for just-in-time generation of instance attribute """
def __init__(self, name, font, antialias, color, background):
self.data = name, font, antialias, color, background
def __get__(self, obj, cls=None):
name, font, antialias, color, background = self.data
setattr(obj, name, {let: font.render(let, antialias, color, background)
for let in "ABCDEFGHJKLMNPRSTUVWXZ"})
return getattr(obj, name)
class Trial(object):
font = pygame.font.Font(None, fontsize)
target_dic = AutoAttr('target_dic', font, TRUE, WHITE, BG)
还有其他方法可以做这样的事情,例如使用元类或定义__new__
方法,但是任何方法都可以更好地工作或者更复杂。
答案 2 :(得分:-1)
在创建类时可用的名称是全局变量,并且在类的顶层定义了名称已经(也就是说,当名称被定义时,它们在课程的下方可用码)。
请注意,类级别的对象可能不是通过实例获取它们,甚至不是通过类对象获取它们;最值得注意的是,在课堂创作过程中,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)
这会产生:
{'A': 'foo', 'C': 'foo', 'B': 'foo', 'E': 'foo', 'D': 'foo', 'G': 'foo', 'F': 'foo', 'H': 'foo', 'K': 'foo', 'J': 'foo', 'M': 'foo', 'L': 'foo', 'N': 'foo', 'P': 'foo', 'S': 'foo', 'R': 'foo', 'U': 'foo', 'T': 'foo', 'W': 'foo', 'V': 'foo', 'X': 'foo'}
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'U', 'V', 'W', 'X']
(http://ideone.com/aC7VY)
正如预期的那样, font
可以传递给lambda。
问题不在于课程范围内可用的名称(font
可用)。问题是理解引入了他们自己的新范围(在python 3中):http://docs.python.org/py3k/reference/expressions.html#displays-for-lists-sets-and-dictionaries