查找with:Block中定义的函数

时间:2009-08-10 16:38:03

标签: python scope with-statement contextmanager

以下是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

2 个答案:

答案 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

(这个想法类似于标签是如何用文字制作的,按钮是由文字和功能组成的)