pygtk:在封闭作用域中引用了未赋值的自由变量
我遇到了一个很奇怪的作用域错误,连我自己都看不明白。在一个更新函数里面,我有一个嵌套的辅助函数,用来帮忙处理一些事情:
def attach_row(ws,r1,r2):
es = []
for i,w in enumerate(ws):
eb = gtk.EventBox()
a = gtk.Alignment(xalign=0.0,yalign=0.5)
a.add(w)
eb.add(a)
eb.set_style(self.rowStyle.copy())
es.append(eb)
self.table.attach(eb, i, i+1, r1, r2,
xoptions=gtk.EXPAND|gtk.FILL,
yoptions=gtk.SHRINK)
def ene(_,ev):
for eb in es:
eb.set_state(gtk.STATE_PRELIGHT)
def lne(_,ev):
for eb in es:
eb.set_state(gtk.STATE_NORMAL)
for eb in es:
eb.connect('enter-notify-event', ene)
eb.connect('leave-notify-event', lne)
这个代码偶尔能正常工作,但如果update()函数运行得太频繁,我最终会遇到:
for eb in es:
NameError: free variable 'es' referenced before assignment in enclosing scope
这是什么原因造成的呢?es肯定是在这些函数被调用之前就已经赋值了,对吧?难道发生了什么奇怪的事情,比如说在创建新行的时候,之前创建的行的ene()被调用了,而这个时候被闭包的es
又被覆盖了?
2 个回答
0
我刚注册,没足够的积分来评论……
- 全局或者更高层级没有名为 'es' 的变量吗?
- attach_row 不是一个嵌套函数吗?
- NameError 异常指向 ene 或 lne 函数中的 for 循环那一行吗?
一个可能的解决办法,但有点麻烦,可能是把 ene 和 lne 做成类,然后通过一个 __call__() 方法让它们像函数一样被调用。
4
这确实挺神秘的——看起来闭包在内部函数中消失了。我在想这是不是和 pygtk 如何处理这些回调函数有关(我对它的内部机制不太了解)。为了探究这个问题——如果你在 attach_row
的最后把 ene
和 lne
也添加到一个全局列表中,确保它们在某个地方“正常”保存,这样它们的闭包就能存活——这样做后问题还会存在吗?
如果问题依然存在,那我得承认这个问题实在是太神秘了,我同意之前的回答,建议使用一些更清晰的方式来保存状态的可调用对象(我建议用一个类实例的两个绑定方法,因为它们共享状态,但用两个单独的类实例,配合 __call__
方法,并在它的 __init__
中接收要设置的状态和事件框列表,这也是合理的——我认为有两个独立的类有点夸张;-)。