Python如何获取调用函数(不仅仅是其名称)?

发布于 2021-01-29 17:24:49

我想编写一个返回调用函数的函数:

def foo():
    return get_calling_function() #should return 'foo' function object

在线上有许多示例,这些示例如何获取调用函数的 名称
,而不是如何获取实际对象。我提出了以下解决方案,该解决方案获取名称,然后在调用函数的全局名称空间中查找它。但是,这对于类函数不起作用,因为在那里您还需要类名,并且我想像还有很多其他的边缘情况。

from inspect import stack
def get_calling_function():
    return stack()[2][0].f_globals[stack()[1][3]]

因此,是否有任何建议如何或是否有可能编写此函数以使其能够正常运行(在Python 3上,btw)?谢谢。

关注者
0
被浏览
239
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    可以从任何代码对象(和扩展模块/内置)调用:从execexecfile在模块名称空间(在导入期间),在类定义内,在方法/类方法/静态方法内,从修饰的函数/方法内,从嵌套函数中…,因此通常没有“调用函数”,并且很难做到这一点。

    堆栈框架及其代码对象是最常用的-检查属性。


    在许多情况下,这可以找到调用函数:

    import sys, inspect
    
    def get_calling_function():
        """finds the calling function in many decent cases."""
        fr = sys._getframe(1)   # inspect.stack()[1][0]
        co = fr.f_code
        for get in (
            lambda:fr.f_globals[co.co_name],
            lambda:getattr(fr.f_locals['self'], co.co_name),
            lambda:getattr(fr.f_locals['cls'], co.co_name),
            lambda:fr.f_back.f_locals[co.co_name], # nested
            lambda:fr.f_back.f_locals['func'],  # decorators
            lambda:fr.f_back.f_locals['meth'],
            lambda:fr.f_back.f_locals['f'],
            ):
            try:
                func = get()
            except (KeyError, AttributeError):
                pass
            else:
                if func.__code__ == co:
                    return func
        raise AttributeError("func not found")
    
    # Usage
    
    def f():
        def nested_func():
            print get_calling_function()
        print get_calling_function()
        nested_func()
    
    class Y:
        def meth(self, a, b=10, c=11):
            print get_calling_function()
            class Z:
                def methz(self):
                    print get_calling_function()
            z = Z()
            z.methz()
            return z
        @classmethod
        def clsmeth(cls):
            print get_calling_function()
        @staticmethod
        def staticmeth():
            print get_calling_function()
    
    f()
    y = Y()
    z = y.meth(7)
    z.methz()
    y.clsmeth()
    ##y.staticmeth()  # would fail
    

    它发现:

    <function f at 0x012E5670>
    <function nested_func at 0x012E51F0>
    <bound method Y.meth of <__main__.Y instance at 0x01E41580>>
    <bound method Z.methz of <__main__.Z instance at 0x01E63EE0>>
    <bound method Z.methz of <__main__.Z instance at 0x01E63EE0>>
    <bound method classobj.clsmeth of <class __main__.Y at 0x01F3CF10>>
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看