Определить имя функции из этой функции (без использования traceback) - PullRequest
382 голосов
/ 21 февраля 2011

В Python, без использования модуля traceback, есть ли способ определить имя функции из этой функции?

Скажем, у меня есть модуль foo с функциональной панелью.При выполнении foo.bar() есть ли способ, чтобы бар узнал имя бара?Или еще лучше, имя foo.bar?

#foo.py  
def bar():
    print "my name is", __myname__ # <== how do I calculate this at runtime?

Ответы [ 20 ]

345 голосов
/ 21 февраля 2011
import inspect

def foo():
   print(inspect.stack()[0][3])
157 голосов
/ 21 февраля 2011

Python не имеет функции для доступа к функции или ее имени внутри самой функции. Он был предложен , но отклонен. Если вы не хотите играть со стеком самостоятельно, вы должны использовать "bar" или bar.__name__ в зависимости от контекста.

Данное уведомление об отказе:

Этот PEP отклонен. Неясно, как это должно быть реализовано или какой должна быть точная семантика в крайних случаях, и дано недостаточно важных вариантов использования. Ответ был в лучшем случае теплым.

128 голосов
/ 28 июня 2013

Есть несколько способов получить тот же результат:

from __future__ import print_function
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
43 голосов
/ 21 февраля 2011

Вы можете получить имя, которое было определено с помощью подхода, который @Andreas Jung показывает , но это может быть не то имя, с которым была вызвана функция:

import inspect

def Foo():
   print inspect.stack()[0][3]

Foo2 = Foo

>>> Foo()
Foo

>>> Foo2()
Foo

Важно ли это различие для вас или нет, я не могу сказать.

36 голосов
/ 31 марта 2013
functionNameAsString = sys._getframe().f_code.co_name

Я хотел очень похожую вещь, потому что хотел поместить имя функции в строку журнала, которая вошла в ряд мест в моем коде. Возможно, это не лучший способ сделать это, но вот способ получить имя текущей функции.

20 голосов
/ 08 июля 2014

Я держу эту удобную утилиту поблизости:

import inspect
myself = lambda: inspect.stack()[1][3]

Использование:

myself()
20 голосов
/ 21 февраля 2011

Я думаю, inspect - лучший способ сделать это. Например:

import inspect
def bar():
    print("My name is", inspect.stack()[0][3])
14 голосов
/ 25 ноября 2013

Я нашел оболочку, которая напишет имя функции

from functools import wraps

def tmp_wrap(func):
    @wraps(func)
    def tmp(*args, **kwargs):
        print func.__name__
        return func(*args, **kwargs)
    return tmp

@tmp_wrap
def my_funky_name():
    print "STUB"

my_funky_name()

Это напечатает

my_funky_name

STUB

11 голосов
/ 24 июля 2015

Это на самом деле вытекает из других ответов на вопрос.

Вот мое мнение:

import sys

# for current func name, specify 0 or no argument.
# for name of caller of current func, specify 1.
# for name of caller of caller of current func, specify 2. etc.
currentFuncName = lambda n=0: sys._getframe(n + 1).f_code.co_name


def testFunction():
    print "You are in function:", currentFuncName()
    print "This function's caller was:", currentFuncName(1)    


def invokeTest():
    testFunction()


invokeTest()

# end of file

Вероятное преимущество этой версии перед использованием inspect.stack () состоит в том, чтодолжно быть в тысячи раз быстрее [см. сообщение Алекса Мелихоффа и время его использования sys._getframe () по сравнению с inspect.stack ()]. ​​

11 голосов
/ 08 января 2016

print(inspect.stack()[0].function), кажется, тоже работает (Python 3.5).

...