以下是Richard Jones' Blog的一些代码:
with gui.vertical:
text = gui.label('hello!')
items = gui.selection(['one', 'two', 'three'])
with gui.button('click me!'):
def on_click():
text.value = items.value
text.foreground = red
我的问题是:他是怎么做到的?上下文管理器如何访问with块内的范围?这是尝试解决这个问题的基本模板:
from __future__ import with_statement
class button(object):
def __enter__(self):
#do some setup
pass
def __exit__(self, exc_type, exc_value, traceback):
#XXX: how can we find the testing() function?
pass
with button():
def testing():
pass
答案 0 :(得分:12)
这是一种方式:
from __future__ import with_statement
import inspect
class button(object):
def __enter__(self):
# keep track of all that's already defined BEFORE the `with`
f = inspect.currentframe(1)
self.mustignore = dict(f.f_locals)
def __exit__(self, exc_type, exc_value, traceback):
f = inspect.currentframe(1)
# see what's been bound anew in the body of the `with`
interesting = dict()
for n in f.f_locals:
newf = f.f_locals[n]
if n not in self.mustignore:
interesting[n] = newf
continue
anf = self.mustignore[n]
if id(newf) != id(anf):
interesting[n] = newf
if interesting:
print 'interesting new things: %s' % ', '.join(sorted(interesting))
for n, v in interesting.items():
if isinstance(v, type(lambda:None)):
print 'function %r' % n
print v()
else:
print 'nothing interesting'
def main():
for i in (1, 2):
def ignorebefore():
pass
with button():
def testing(i=i):
return i
def ignoreafter():
pass
main()
编辑:拉伸代码多一点,添加了一些解释......:
在 我还添加了一个循环(以便更加确定正确处理之前/之后/之后的__exit__
抓取来电者的本地人很容易 - 更难以避免那些已经在 with
区块之前已经定义的本地人,这就是为什么我添加到主要的两个本地with
应忽略的函数。我对这个看起来有点复杂的解决方案并不是百分之百满意,但我无法使用==
或is
进行正确的测试,所以我采用了这种相当复杂的方法。 / p>
def
)以及类型检查和函数调用以确保{的正确化身{ {1}}是已识别出来的(一切似乎工作正常) - 当然,只有testing
内的def
用于不带参数可调用的函数,所写的代码才有效,它不是难以获得with
的签名以防止这种情况(但是因为我只是为了检查正确的函数对象是否被识别而进行调用,所以我没有理会这个最后的细化;-)
答案 1 :(得分:1)
回答你的问题,是的,这是框架内省。
但是我要创建的语法是
with gui.vertical:
text = gui.label('hello!')
items = gui.selection(['one', 'two', 'three'])
@gui.button('click me!')
class button:
def on_click():
text.value = items.value
text.foreground = red
在这里,我将实现gui.button
作为装饰器,在给定一些参数和事件的情况下返回按钮实例(尽管我现在觉得button = gui.button('click me!', mybutton_onclick
也很好)。
我也会离开gui.vertical
,因为它可以在没有内省的情况下实现。我不确定它的实现,但可能涉及设置gui.direction = gui.VERTICAL
,以便gui.label()
和其他人在计算坐标时使用它。
现在,当我看到这个时,我想我会尝试语法:
with gui.vertical:
text = gui.label('hello!')
items = gui.selection(['one', 'two', 'three'])
@gui.button('click me!')
def button():
text.value = items.value
foreground = red
(这个想法类似于标签是如何用文字制作的,按钮是由文字和功能组成的)