从框架中获取可调用对象

时间:2009-07-15 16:41:40

标签: python

给定框架对象(例如,由sys._getframe返回),我可以获取底层可调用对象吗?

代码说明:

def foo():
    frame = sys._getframe()
    x = some_magic(frame)

    # x is foo, now

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

希望这是可能的。

干杯,

MH

修改

我有点设法解决这个问题。安德烈亚斯和亚历山大的回复深受启发。谢谢各位投入的时间!

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__

然后,我可以积极遍历globals()或gc.get_objects()和dir()所有内容,以搜索具有给定函数对象的callable。

对我来说感觉有点不熟悉,但是有效。

再次感谢!

MH

3 个答案:

答案 0 :(得分:1)

为了支持所有情况,包括函数是类的一部分或只是一个全局函数,没有直接的方法来做到这一点。您可能能够获得完整的调用堆栈并在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)

答案 1 :(得分:1)

有点难看,但现在是:

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 :(得分:0)

不是答案,而是评论。我将其添加为评论,但我没有足够的"声誉点"。

对于它的价值,这是一个合理的(我认为)用例,想要做这类事情。

我的应用程序使用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(或其他)来计算可调用和args以传递给idle_add(),然后返回True。获得我能弄明白的args。获得可调用性似乎并不太容易。 : - (