代码之家  ›  专栏  ›  技术社区  ›  Mike Hordecki

从帧中获取可调用对象

  •  3
  • Mike Hordecki  · 技术社区  · 15 年前

    给定帧对象(返回 sys._getframe 例如,我能得到下面的可调用对象吗?

    代码说明:

    def foo():
        frame = sys._getframe()
        x = some_magic(frame)
    
        # x is foo, now
    

    请注意,我的问题是将对象从帧中取出,而不是当前调用的对象。

    希望那是可能的。

    干杯,

    马来酸酐

    编辑:

    我已经设法解决了这个问题。它深受安德烈亚斯和亚力山大的回答启发。感谢大家投入时间!

    def magic():
        fr = sys._getframe(1)
        for o in gc.get_objects():
            if inspect.isfunction(o) and o.func_code is fr.f_code:
                return o 
    
    class Foo(object):
        def bar(self):
            return magic()
    
    x = Foo().bar()
    
    assert x is Foo.bar.im_func

    (在2.6.2中工作,对于PY3K替换 func_code 具有 __code__ im_func 具有 __func__ )

    然后,我可以积极遍历GULL()或GC.GETYObjutsSe()和DIR(),以查找给定函数对象的可调用的所有内容。

    我觉得有点言不由衷,但行得通。

    再次感谢!

    马来酸酐

    3 回复  |  直到 9 年前
        1
  •  1
  •   Alexander Ljungberg    15 年前

    有点难看,但这里是:

    frame.f_globals[frame.f_code.co_name]
    

    完整示例:

    #!/usr/bin/env python
    
    import sys
    
    def foo():
      frame = sys._getframe()
      x = frame.f_globals[frame.f_code.co_name]
    
      print foo is x
    
    foo()
    

    打印“真”。

        2
  •  1
  •   Blixt    15 年前

    要支持所有情况,包括函数是类的一部分或只是全局函数,没有直接的方法可以做到这一点。您可能能够获得完整的调用堆栈并通过迭代向下遍历 globals() ,但这不太好……

    我能得到的最接近的是:

    import sys, types
    
    def magic():
        # Get the frame before the current one (i.e. frame of caller)
        frame = sys._getframe(1)
        # Default values and closure is lost here (because they belong to the
        # function object.)
        return types.FunctionType(frame.f_code, frame.f_globals)
    
    class MyClass(object):
        def foo(self, bar='Hello World!'):
            print bar
            return magic()
    
    test = MyClass()
    
    new_foo = test.foo()
    new_foo(test, 'Good Bye World!')
    

    您将执行完全相同的代码,但它将位于新的代码包装器中(例如, FunctionType )

    我怀疑您希望能够基于堆栈还原应用程序的状态…这里至少会调用函数与原始调用尽可能相似(闭包仍然被忽略,因为如果可以从框架中获得闭包,得到调用的函数将非常容易):

    import sys, types
    
    class MyClass(object):
        def __init__(self, temp):
            self.temp = temp
    
        def foo(self, bar):
            print self.temp, bar
            return sys._getframe()
    
    def test(hello):
        print hello, 'World!'
        return sys._getframe()
    
    def recall(frame):
        code = frame.f_code
        fn = types.FunctionType(
            code, frame.f_globals, code.co_name,
            # This is one BIG assumption that arguments are always last.
            tuple(frame.f_locals.values()[-code.co_argcount:]))
        return fn()
    
    
    test1 = MyClass('test1')
    frame1 = test1.foo('Hello World!')
    
    test2 = MyClass('test2')
    frame2 = test2.foo('Good Bye World!')
    frame3 = test2.foo('Sayonara!')
    
    frame4 = test('HI')
    
    print '-'
    
    recall(frame4)
    recall(frame3)
    recall(frame2)
    recall(frame1)
    
        3
  •  0
  •   Phil    9 年前

    不是一个真正的答案,而是一个评论。我想补充一下,但我没有足够的“信誉点”。

    就其价值而言,这里有一个合理的(我认为)用例来实现这类事情。

    我的应用程序使用gtk,并旋转了许多线程。任何一个同时都知道的人,你不能触摸主线程外部的GUI。一个典型的解决方法是将触摸gui的可调用的 idle_add() ,稍后将在主线程中安全运行它。所以我有一个 许多 发生次数:

    def threaded_gui_func(self, arg1, arg2):
        if threading.currentThread().name != 'MainThread':
            gobject.idle_add(self.threaded_gui_func, arg1, arg2)
            return
        # code that touches the GUI
    

    如果我能做到的话,它会短一点,容易一点(而且更有利于剪切粘贴)

    def thread_gui_func(self, arg1, arg2):
        if idleIfNotMain(): return
        # code that touches the GUI
    

    其中,如果我们在主线程中,idleifnotmain()只返回false,如果不在主线程中,则使用inspect(或其他方法)计算出要传递给 IDLIADAd() ,然后返回true。得到的ARG我可以计算出来。获取可调用的似乎不太容易。: