Python如何获得调用函数(不只是它的名字)? [英] Python how to get the calling function (not just its name)?

查看:221
本文介绍了Python如何获得调用函数(不只是它的名字)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  def foo() :
return get_calling_function()#应该返回'foo'函数对象

如何获取调用函数的名称,但不知道如何获取实际的对象。我想出了以下解决方案,获取名称,然后在调用函数的全局名称空间中查找它。然而,这不适用于类函数,因为在那里你也需要类名称,而且我还有一些其他的边缘案例。

from inspect import stack
def get_calling_function():
return stack ()[b] [b] [b] [b] [b]因此,任何建议如何或如果它可能编写这个函数,以便它一般工作(在Python 3,btw)?谢谢。

解决方案

调用可以从任何代码对象(以及来自扩展模块/内建)发生:from exec execfile ,从模块名称空间(导入期间),从类定义内,从方法/类方法/静态方法,函数/方法,从一个嵌套函数中,... - 所以一般没有调用函数,并且很难做到这一点。



栈帧和它们的代码对象是你可以得到的最一般的东西 - 并检查属性。






这个找到在很多情况下调用函数:

pre $ import sys,检查

def get_calling_function():$ b $
fr = sys._getframe(1)#inspect.stack()[1] [0]
co = fr.f_code
for get(
lambda:fr.f_globals [co.co_name],
lambda:get attr(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],#嵌套
lambda:fr.f_back.f_locals ['func'],#decorators
lambda:fr.f_back.f_locals ['meth'],
lambda:fr .f_back.f_locals ['f'],
):
尝试:
func = get()
除了(KeyError,AttributeError):
传递
else:
if func .__ code__ == co:
return func
raise AttributeError(func not found)

#用法

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()
返回z
@classmethod
def clsmeth(cls):
print get_calling_function()
@staticmethod
def staticmeth():
print get_calling_function()
$ bf()
y = Y()
z = y.meth(7)
z.methz()
y.clsmeth()
## y.staticmeth()#会失败

它发现:

 <函数f at 0x012E5670> 
< function nested_func at 0x012E51F0>
< bound method Y.meth of< __main __ .Y instance at 0x01E41580>>
< __main __的边界方法Z.methz; 0x01E63EE0处的Z实例>>
< __main __的边界方法Z.methz; 0x01E63EE0处的Z实例>>
< class __main __的绑定方法classobj.clsmeth在0x01F3CF10处的Y>>


I want to write a function which returns the calling function:

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

There's numerous examples online how to get the calling function's name, but not how to get the actual object. I've come up with the following solution which gets the name, then looks it up in the calling function's global namespace. However this doesn't work for class functions since there you need the class name as well, and I image there's a bunch of other edge cases as well.

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

So any advice how or if its possible to write this function so that it works generically (on Python 3, btw)? Thanks.

解决方案

Calling can happen from any code object (and from an extension module/builtin): from exec, execfile, from module name space (during import), from within a class definition, from within a method / classmethod / staticmethod, from a decorated function/method, from within a nested function, ... - so there is no "calling function" in general, and the difficulty to do anything good with that.

The stack frames and their code objects are the most general you can get - and examine the attributes.


This one finds the calling function in many cases:

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

It finds:

<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>>

这篇关于Python如何获得调用函数(不只是它的名字)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆