查找在 with: 块中定义的函数 [英] Finding Functions Defined in a with: Block
问题描述
这是来自 Richard Jones 的博客的一些代码:
Here's some code from 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 块内的作用域?这是尝试解决此问题的基本模板:
My question is: how the heck did he do this? How can the context manager access the scope inside the with block? Here's a basic template for trying to figure this out:
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
推荐答案
这是一种方法:
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()
编辑:进一步拉伸代码,添加一些解释...:
Edit: stretched code a bit more, added some explanation...:
在 __exit__
处捕获调用者的本地变量很容易——更棘手的是避免那些在 with
块之前之前定义的本地变量,这就是为什么我添加了 with
应该忽略的主要两个本地函数.我对这个解决方案不是 100% 满意,它看起来有点复杂,但我无法使用 ==
或 is
进行正确的相等性测试,所以我求助于这种相当复杂的方法.
Catching caller's locals at __exit__
is easy -- trickier is avoiding those locals that were already defined before the with
block, which is why I added to main two local functions that the with
should ignore. I'm not 100% happy with this solution, which looks a bit complicated, but I couldn't get equality testing correct with either ==
or is
, so I resorted to this rather complicated approach.
我还添加了一个循环(以更强烈地确保正确处理之前/之内/之后的 def
s)和类型检查和函数调用以确保正确testing
的化身是被识别的(一切似乎都工作正常)——当然,编写的代码只有在 with
中的 def
时才有效code> 用于没有参数的可调用函数,使用 inspect
获取签名并不难(但由于我进行调用只是为了检查正确的函数对象已确定,我没有在意最后的改进;-)
I've also added a loop (to make more strongly sure the def
s before / within / after are being properly handled) and a type-check and function-call to make sure the right incarnation of testing
is the one that's identified (everything seems to work fine) -- of course the code as written only works if the def
inside the with
is for a function callable without arguments, it's not hard to get the signature with inspect
to ward against that (but since I'm doing the call only for the purpose of checking that the right function objects are identified, I didn't bother about this last refinement;-).
这篇关于查找在 with: 块中定义的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!