Определение имени функции изнутри самой функции
Существует ли способ получить название функции изнутри самой функции?
def foo():
print("my name is", __myname__) # <== как мне узнать это во время выполнения?
В приведенном выше примере тело функции foo
должно каким-то образом получить имя функции "foo"
без жесткого кодирования. Ожидаемый вывод будет таким:
>>> foo()
my name is foo
5 ответ(ов)
Ваш код использует модуль inspect
для получения информации о стеке вызовов функций. Давайте разберем, как он работает.
В функции foo
вы вызываете inspect.stack()
, которая возвращает список объектов StackEntry, представляющих текущий вызов стека. Каждый элемент списка содержит информацию о текущем контексте выполнения, включая имя функции, файл и номер строки.
В вашем случае:
inspect.stack()[0][3]
возвращает имя функции, которая в данный момент выполняется, то естьfoo
.inspect.stack()[1][3]
возвращает имя функции или модуля, вызвавшегоfoo
. Если вы вызываетеfoo
из модуля (например, из основного блока программы), это будет<module_caller_of_foo>
(или просто имя модуля).
Так что, полное поведение вашего кода в выводе выглядит следующим образом:
foo # имя текущей функции
<module_caller_of_foo> # имя вызывающего модуля
Важно учитывать, что если бы вы вызывали foo
из другой функции, то имя этой функции было бы выведено вместо <module_caller_of_foo>
.
Есть несколько способов получить одно и то же значение:
import sys
import inspect
def what_is_my_name():
print(inspect.stack()[0][0].f_code.co_name)
print(inspect.stack()[0][3])
print(inspect.currentframe().f_code.co_name)
print(sys._getframe().f_code.co_name)
Обратите внимание, что вызовы inspect.stack
значительно медленнее, чем альтернативы:
$ python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][0].f_code.co_name'
1000 loops, best of 3: 499 usec per loop
$ python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][3]'
1000 loops, best of 3: 497 usec per loop
$ python -m timeit -s 'import inspect, sys' 'inspect.currentframe().f_code.co_name'
10000000 loops, best of 3: 0.1 usec per loop
$ python -m timeit -s 'import inspect, sys' 'sys._getframe().f_code.co_name'
10000000 loops, best of 3: 0.135 usec per loop
Обновление 08/2021 (оригинальный пост был написан для Python 2.7):
Python 3.9.1 (default, Dec 11 2020, 14:32:07)
[GCC 7.3.0] :: Anaconda, Inc. на linux
python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][0].f_code.co_name'
500 loops, best of 5: 390 usec per loop
python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][3]'
500 loops, best of 5: 398 usec per loop
python -m timeit -s 'import inspect, sys' 'inspect.currentframe().f_code.co_name'
2000000 loops, best of 5: 176 nsec per loop
python -m timeit -s 'import inspect, sys' 'sys._getframe().f_code.co_name'
5000000 loops, best of 5: 62.8 nsec per loop
Таким образом, если вам нужно получить имя текущей функции, рассчитывайте на использование inspect.currentframe()
или sys._getframe()
, так как они значительно быстрее.
Вы можете получить имя текущей функции, используя следующий код:
functionNameAsString = sys._getframe().f_code.co_name
Я хотел сделать нечто подобное, чтобы вставить имя функции в строку логирования, которая использовалась в различных местах моего кода. Возможно, это не самый лучший способ, однако вот как можно получить имя текущей функции.
Это на самом деле является производным из других ответов на вопрос.
Вот мой подход:
import sys
# Для получения имени текущей функции укажите 0 или не передавайте аргумент.
# Для имени вызывающей функции текущей функции укажите 1.
# Для имени вызывающей функции вызывающей функции текущей функции укажите 2 и так далее.
currentFuncName = lambda n=0: sys._getframe(n + 1).f_code.co_name
def testFunction():
print("Вы находитесь в функции:", currentFuncName())
print("Эта функция была вызвана из:", currentFuncName(1))
def invokeTest():
testFunction()
invokeTest()
# конец файла
Вероятное преимущество данного подхода по сравнению с использованием inspect.stack()
заключается в том, что он должен работать в тысячи раз быстрее [см. пост Алекса Мелихова и замеры относительно использования sys._getframe()
по сравнению с inspect.stack()
].
Вы можете использовать следующий полезный инструмент для получения имени текущей функции:
import inspect
myself = lambda: inspect.stack()[1][3]
Пример использования:
myself()
Этот код определяет лямбда-функцию myself
, которая возвращает имя функции, из которой она была вызвана. Это может быть полезно для отладки или логирования, чтобы видеть, в какой функции вы находитесь в данный момент.
Как получить имя функции в виде строки?
Получить все атрибуты объекта в Python?
Как применить функцию к двум столбцам DataFrame в Pandas
Как получить исходный код функции Python?
Как получить возвращаемое значение из потока?