Python как получить вызывающую функцию (а не только ее имя)?
Я хочу написать функцию, которая возвращает вызывающую функцию:
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, кстати)? Благодарю.
1 ответ
Вызов может происходить из любого объекта кода (и из модуля расширения / встроенного): из exec
, execfile
из пространства имен модуля (во время импорта), из определения класса, из метода / classmethod / staticmethod, из декорированной функции / метода, из вложенной функции, ... - так что нет "вызывающей функции" в общем и сложность сделать что нибудь хорошее с этим.
Кадры стека и их объекты кода являются наиболее общими, которые вы можете получить, - и изучите атрибуты.
Этот находит вызывающую функцию во многих случаях:
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>>