查找在 with: 块中定义的函数 [英] Finding Functions Defined in a with: Block

查看:34
本文介绍了查找在 with: 块中定义的函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是来自 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.

我还添加了一个循环(以更强烈地确保正确处理之前/之内/之后的 defs)和类型检查和函数调用以确保正确testing 的化身是被识别的(一切似乎都工作正常)——当然,编写的代码只有在 with 中的 def 时才有效code> 用于没有参数的可调用函数,使用 inspect 获取签名并不难(但由于我进行调用只是为了检查正确的函数对象已确定,我没有在意最后的改进;-)

I've also added a loop (to make more strongly sure the defs 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆