Python 查找with:块中定义的函数

Python 查找with:块中定义的函数,python,scope,with-statement,contextmanager,Python,Scope,With Statement,Contextmanager,以下是来自的一些代码: 我的问题是:他到底是怎么做到的?上下文管理器如何访问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

以下是来自的一些代码:

我的问题是:他到底是怎么做到的?上下文管理器如何访问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
这里有一个方法:

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()
编辑:进一步扩展代码,添加一些解释…:

\uuuu exit\uuuu
处捕获调用方的局部变量很容易——更棘手的是避免那些在
with
块之前已经定义的局部变量,这就是为什么我添加到
with
应该忽略的两个主要局部函数中。我对这个解决方案不是100%满意,它看起来有点复杂,但我无法用
==
is
进行正确的平等性测试,所以我采用了这个相当复杂的方法


我还添加了一个循环(以更有力地确保
def
s before/in/after得到正确处理)和一个类型检查和函数调用,以确保
测试的正确体现是已确定的(一切似乎都正常工作)--当然,编写的代码只有在
with
中的
def
用于无参数调用的函数时才起作用,因此不难通过
inspect
获得签名来避免这种情况(但由于我调用函数只是为了检查是否识别了正确的函数对象,所以我没有考虑最后的优化;-)。

回答您的问题,是的,这是框架内省

但是我会创建语法来做同样的事情

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\u 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

(其思想类似于标签是由文本组成的,按钮是由文本和功能组成的)

但是为什么要使用“with gui.vertical”?它需要执行相同的堆栈内省来访问其中的文本、项目和按钮。我确信您可以执行类似的操作:class MyLayout(gui.vertical):text=gui.label('hello!')#等等,对吗?不管怎样,我很清楚这是对with block的严重非标准滥用。我只是想知道他是怎么做到的。我希望你至少看到这是对with block的一种很酷的滥用:)我用gui.vertical阅读
“不创建元素,但确保在此上下文中创建的所有元素都从当前点垂直计算其坐标”。无需内省。不客气!这是一个有趣的问题,因此,提出它;-)。我发布了一篇博客文章,介绍如何使用您给我的代码,以防您感兴趣:
    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