lli*_*lib 11 python scope with-statement contextmanager
以下是Richard Jones博客的一些代码:
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
Run Code Online (Sandbox Code Playgroud)
我的问题是:他是怎么做到的?上下文管理器如何访问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
Run Code Online (Sandbox Code Playgroud)
Ale*_*lli 14
这是一种方式:
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()
Run Code Online (Sandbox Code Playgroud)
编辑:拉伸代码多一点,添加一些解释......:
在追赶呼叫者的当地人__exit__很简单-麻烦是避免那些已经定义的那些当地人之前的with块,这就是为什么我添加到两个主要的本地函数的with应该忽略.我不是很满意这个解决方案,这看起来有点复杂的100%,但我无法得到平等对待的正确测试无论用==或者is,所以我使出这个相当复杂的方法.
我还添加了一个循环(以更加确定def正确处理之前/之内/之后的s)以及类型检查和函数调用以确保正确的化身testing是已识别的(所有似乎都是工作正常) - 当然所写的代码只有def在with函数可以调用而没有参数的情况下才有效,所以不难获得签名inspect(但是因为我只是为了这个目的而打电话)检查确定了正确的功能对象,我没有理会这个最后的改进;-).
| 归档时间: |
|
| 查看次数: |
1098 次 |
| 最近记录: |