查找 with: 块中定义的函数

发布于 2024-07-30 14:38:56 字数 764 浏览 7 评论 0原文

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

我的问题是:如何到底他是这么做的吗? 上下文管理器如何访问 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

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

对你而言 2024-08-06 14:38:57

回答你的问题,是的,这就是框架内省。

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

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

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

To answer your question, yes, it's frame introspection.

But the syntax I would create to do the same thing is

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

Here I would implement gui.button as a decorator that returns button instance given some parameters and events (though it appears to me now that button = gui.button('click me!', mybutton_onclick is fine as well).

I would also leave gui.vertical as it is since it can be implemented without introspection. I'm not sure about its implementation, but it may involve setting gui.direction = gui.VERTICAL so that gui.label() and others use it in computing their coordinates.

Now when I look at this, I think I'd try the syntax:

    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

(the idea being that similarly to how label is made out of text, a button is made out of text and function)

孤星 2024-08-06 14:38:56

这是一种方法:

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 块之前,这就是为什么我在 main 中添加了 with 应该忽略的两个本地函数。 我对这个解决方案并不是 100% 满意,它看起来有点复杂,但我无法使用 ==is 进行正确的相等测试,所以我求助于对于这种相当复杂的方法。

我还添加了一个循环(以更加有力地确保正确处理之前/之内/之后的 def)和类型检查和函数调用,以确保 def 的正确体现code>testing 是已识别的(一切似乎都工作正常)——当然,只有当 with 内的 def 为对于不带参数的可调用函数,使用 inspect 获取签名来防止这种情况并不难(但由于我进行调用只是为了检查是否识别了正确的函数对象,我没有关心这最后的改进;-)。

Here's one way:

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...:

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.

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;-).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文