Python не имеет функции доступа к функции или ее имени внутри самой функции. Было предложено , но отклонено. Если вы не хотите играть со стеком самостоятельно, вы должны либо использовать "bar"
, либо bar.__name__
в зависимости от контекста.
Данное уведомление об отказе:
Этот PEP отклонен. Непонятно, как это должно быть реализовано или какая должна быть точная семантика в крайних случаях, и недостаточно данных важных случаев использования. ответ был в лучшем случае теплым.
Я думаю, inspect
- лучший способ сделать это. Пример:
import inspect
def bar():
print "My name is", inspect.stack()[0][3]
Я нашел обертку, которая будет писать имя функции
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
< / BLOCKQUOTE>
my_funky_name.__name__
. Вы можете передать func .__ name__ в функцию как новый параметр. func (* args, ** kwargs, my_name = func .__ name__). Чтобы получить имя вашего декоратора изнутри вашей функции, я думаю, что это потребует использования проверки. Но получить имя функции, управляющей моей функцией, в моей текущей функции ... ну, это просто похоже на начало красивого мема :)
– cad106uk
2 July 2017 в 13:00
Я сделал то, что сказал CamHart:
import sys
def myFunctionsHere():
print(sys._getframe().f_code.co_name)
myFunctionsHere()
Выход:
C: \ Python \ Python36 \ python.exe C: / Python / GetFunctionsNames / TestFunctionsNames. py myFunctionsHere
Процесс завершен кодом выхода 0
blockquote>
functionNameAsString = sys._getframe().f_code.co_name
Мне нужна была очень похожая вещь, потому что я хотел поместить имя функции в строку журнала, которая попала в ряд мест в моем коде. Вероятно, это не лучший способ сделать это, но вот способ получить имя текущей функции.
Вот перспективный подход.
Объединение предложений @ CamHart и @ Yuval с принятым ответом @ RoshOxymoron имеет преимущество:
_hidden
и потенциально устаревшие методы Поэтому я думаю, что это хорошо сочетается с будущими версиями 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))
.func_name
. Стоит помнить, что имена классов и имена функций в Python - это одно, а переменные, относящиеся к ним, - это другое.
– Kos
13 December 2012 в 13:48
Foo2()
для печати Foo
. Например: Foo2 = function_dict['Foo']; Foo2()
. В этом случае Foo2 является указателем на функцию, возможно, для синтаксического анализа командной строки.
– Harvey
1 June 2013 в 21:02
Вы можете использовать декоратор:
def my_function(name=None):
return name
def get_function_name(function):
return function(name=function.__name__)
>>> get_function_name(my_function)
'my_function'
Есть несколько способов получить один и тот же результат:
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
0.1python usec per loop
означает нормальный 0.1 usec
, или это какой-то другой (более pythonic) usec?
– mbdevpl
8 July 2016 в 11:24
inspect.currentframe()
кажется хорошим компромиссом между временем выполнения и использованием частных членов
– FabienAndre
27 August 2016 в 09:44
0.100 usec
или 0.199 usec
, но в любом случае - в сотни раз быстрее, чем варианты 1 и 2, сравнимые с вариантом 4 (хотя Антоний Хэтчкинс нашел вариант 3 в три раза быстрее, чем вариант 4).
– dwanderson
13 January 2017 в 17:03
Это на самом деле вытекает из других ответов на вопрос.
Вот мой прием:
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 ()].
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 код выводит
hello, я foo, daddy is
hello, я bar, daddy is foo
привет, я баре, папа
blockquote>
Я использую свой подход, используемый для вызова супер с безопасностью внутри сценария множественного наследования (я положил весь код)
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()
output:
called from C
called from A
called from B
Внутри каждого метода с украшением @with_name у вас есть доступ к self .__ fname__ в качестве текущего имени функции.
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
print(inspect.stack()[0].function)
, похоже, тоже работает (Python 3.5).
import inspect
def foo():
print(inspect.stack()[0][3])
[1][3]
, чтобы получить имя вызывающего абонента.
– Kos
13 December 2012 в 13:47
print(inspect.currentframe().f_code.co_name)
или получить имя вызывающего абонента: print(inspect.currentframe().f_back.f_code.co_name)
. Я думаю, что это должно быть быстрее, так как вы не извлекаете список всех фреймов стека, как это делает inspect.stack()
.
– Michael
23 February 2014 в 12:25
inspect.currentframe().f_back.f_code.co_name
не работает с декорированным способом, тогда как inspect.stack()[0][3]
делает ...
– Dustin Wyatt
15 February 2016 в 19:08
Я поддерживаю эту удобную утилиту рядом:
import inspect
myself = lambda: inspect.stack()[1][3]
Использование:
myself()
inspect.currentframe()
- один из таких способов. – Yuval 20 September 2014 в 11:47print(inspect.currentframe().f_code.co_name)
– hobs 17 March 2015 в 22:43