Определить имя функции из этой функции (без использования отладочных)
в Python, без использования traceback
модуль, есть ли способ определить имя функции из этой функции?
скажем, у меня есть модуль foo с функциональной панелью. При выполнении foo.bar()
, есть ли способ для бара узнать имя бара? Или еще лучше, foo.bar
имя?
#foo.py
def bar():
print "my name is", __myname__ # <== how do I calculate this at runtime?
18 ответов
Python не имеет функции для доступа к функции или ее имени внутри самой функции. Это было предложил но отверг. Если вы не хотите играть со стеком себя, вы должны использовать "bar"
или bar.__name__
в зависимости от контекста.
данное уведомление об отказе-это:
этот PEP отклоняется. Неясно, как это должно быть реализовано или какая точная семантика должна быть в крайних случаях, и их недостаточно приведены важные случаи использования. реакция была в лучшем случае теплой.
есть несколько способов получить тот же результат:
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
вы можете получить имя, которое было определено с помощью подход, который показывает @Andreas Jung, но это может быть не имя, с которым была вызвана функция:
import inspect
def Foo():
print inspect.stack()[0][3]
Foo2 = Foo
>>> Foo()
Foo
>>> Foo2()
Foo
важно ли это различие для вас или нет, я не могу сказать.
functionNameAsString = sys._getframe().f_code.co_name
Я хотел очень похожую вещь, потому что я хотел поместить имя функции в строку журнала, которая шла в нескольких местах в моем коде. Вероятно, это не лучший способ сделать это, но вот способ получить имя текущей функции.
Я держу эту удобную утилиту рядом:
import inspect
myself = lambda: inspect.stack()[1][3]
использование:
myself()
Я нашел оболочку, которая напишет имя функции
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()
выводит
заглушки
это фактически получено из других ответов на вопрос.
вот мое мнение:
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
Это лучший способ, чтобы сделать это. Пример:
import inspect
def bar():
print "My name is", inspect.stack()[0][3]
import inspect
def whoami():
return inspect.stack()[1][3]
def whosdaddy():
return inspect.stack()[2][3]
def foo():
print "hello, I'm %s, daddy is %s" % (whoami(), whosdaddy())
bar()
def bar():
print "hello, I'm %s, daddy is %s" % (whoami(), whosdaddy())
foo()
bar()
в IDE код выводит
Привет, я-фу, папа
Привет, я бар, папа фу
Привет, я бар, папа
import sys
def func_name():
"""
:return: name of caller
"""
return sys._getframe(1).f_code.co_name
class A(object):
def __init__(self):
pass
def test_class_func_name(self):
print(func_name())
def test_func_name():
print(func_name())
тест:
a = A()
a.test_class_func_name()
test_func_name()
выход:
test_class_func_name
test_func_name
вот подход будущего доказательства.
объединение предложений @CamHart и @Yuval с предложениями @RoshOxymoron принято отвечать имеет преимущество избежать:
-
_hidden
и потенциально устаревшие методы - индексирование в стек (который может быть переупорядочен в будущих pythons)
поэтому я думаю, что это хорошо играет с будущими версиями python (протестировано на 2.7.3 и 3.3.2):
from __future__ import print_function
import inspect
def bar():
print("my name is '{}'".format(inspect.currentframe().f_code.co_name))
import sys
def myFunctionsHere():
print(sys._getframe().f_code.co_name)
myFunctionsHere()
выход:
C:\Python\Python36\python.exe C:/Python/GetFunctionsNames/TestFunctionsNames.py myFunctionsHere
процесс завершен с кодом выхода 0
вы можете использовать декоратор:
def my_function(name=None):
return name
def get_function_name(function):
return function(name=function.__name__)
>>> get_function_name(my_function)
'my_function'
Я делаю свой собственный подход, используемый для вызова super с безопасностью внутри сценария множественного наследования (я помещаю весь код)
def safe_super(_class, _inst):
"""safe super call"""
try:
return getattr(super(_class, _inst), _inst.__fname__)
except:
return (lambda *x,**kx: None)
def with_name(function):
def wrap(self, *args, **kwargs):
self.__fname__ = function.__name__
return function(self, *args, **kwargs)
return wrap
пример использования:
class A(object):
def __init__():
super(A, self).__init__()
@with_name
def test(self):
print 'called from A\n'
safe_super(A, self)()
class B(object):
def __init__():
super(B, self).__init__()
@with_name
def test(self):
print 'called from B\n'
safe_super(B, self)()
class C(A, B):
def __init__():
super(C, self).__init__()
@with_name
def test(self):
print 'called from C\n'
safe_super(C, self)()
тестирование это :
a = C()
a.test()
выход:
called from C
called from A
called from B
внутри каждого @ with_name украшенного метода у вас есть доступ к себе.__имени__ в качестве текущего имени функции.
используйте это (на основе ответа #Ron Davis):
import sys
def thisFunctionName():
"""Returns a string with the name of the function it's called from"""
return sys._getframe(1).f_code.co_name
недавно я попытался использовать вышеуказанные ответы для доступа к docstring функции из контекста этой функции, но поскольку вышеуказанные вопросы возвращали только строку имени, она не работала.
к счастью, я нашел простое решение. Если вы хотите обратиться к функции, а не просто получить строку, представляющую имя, вы можете применить eval() к строке имени функции.
import sys
def foo():
"""foo docstring"""
print(eval(sys._getframe().f_code.co_name).__doc__)