Getting callable object from the frame

前端 未结 3 986
悲哀的现实
悲哀的现实 2021-02-06 11:31

Given the frame object (as returned by sys._getframe, for instance), can I get the underlying callable object?

Code explanation:

def foo():
    frame = s         


        
3条回答
  •  盖世英雄少女心
    2021-02-06 12:21

    To support all cases, including the function being part of a class or just a global function, there is no straight-forward way of doing this. You might be able to get the complete call stack and iterate your way down through globals(), but it wouldn't be nice...

    The closest I can get you is this:

    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!')
    

    You'll be executing the exact same code, but it'll be in a new code wrapper (e.g., FunctionType.)

    I suspect you want to be able to restore the state of your application based on a stack... Here's something that will at least call the functions as similarly as possible to the original calls (the closure is still left out, because if you could get closures from the frames, getting the function that was called would be pretty easy):

    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)
    

提交回复
热议问题