从框架中获取可调用对象

Mik*_*cki 7 python

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

代码说明:

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

    # x is foo, now
Run Code Online (Sandbox Code Playgroud)

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

希望这是可能的。

干杯,

MH

编辑:

我在某种程度上设法解决了这个问题。它深受 Andreas 和 Alexander 答复的启发。感谢大家投入的时间!

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
Run Code Online (Sandbox Code Playgroud)

(在2.6.2工作,为py3k替换func_code__code__,并im_func__func__

然后,我可以积极地遍历 globals() 或 gc.get_objects() 和 dir() 一切以搜索具有给定函数对象的可调用对象。

对我来说感觉有点 unpythonic,但有效。

再次感谢!

MH

Bli*_*ixt 2

为了支持所有情况,包括函数作为类的一部分或只是全局函数,没有直接的方法来执行此操作。您也许能够获得完整的调用堆栈并向下迭代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!')
Run Code Online (Sandbox Code Playgroud)

您将执行完全相同的代码,但它将位于新的代码包装器中(例如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)
Run Code Online (Sandbox Code Playgroud)