查找with:Block中定义的函数

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是已识别的(所有似乎都是工作正常) - 当然所写的代码只有defwith函数可以调用而没有参数的情况下才有效,所以不难获得签名inspect(但是因为我只是为了这个目的而打电话)检查确定了正确的功能对象,我没有理会这个最后的改进;-).

  • 别客气!这是一个很有趣的问题,要解决就让TX ;-)。 (2认同)
  • 如果您感兴趣,我发布了一篇博客文章,介绍如何使用您提供的代码:http://billmill.org/multi_line_lambdas.html (2认同)