Как напечатать имя метода / функции с использованием системной переменной Python 3.6 [duplicate]

322
задан Tshepang 7 July 2014 в 10:33
поделиться

20 ответов

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

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

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

117
ответ дан David Foerster 18 August 2018 в 07:49
поделиться
  • 1
    Как вы проголосуете за открытие ОПТОСОЗ? – Scott David Tesler 13 December 2013 в 21:08
  • 2
    sys._getframe (). f_code.co_name Кажется, работает для меня ... – CamHart 11 June 2014 в 21:52
  • 3
    – Tshepang 7 July 2014 в 10:50
  • 4
    inspect.currentframe() - один из таких способов. – Yuval 20 September 2014 в 11:47
  • 5
    Объединение подхода @ CamHart с @ Yuval's избегает & quot; hidden & quot; и, возможно, устаревшие методы в ответе @ RoshOxymoron, а также численное индексирование в стек для ответа @ neuro / @ AndreasJung: print(inspect.currentframe().f_code.co_name) – hobs 17 March 2015 в 22:43
  • 6
    можно ли обобщить, почему его отвергли? – Charlie Parker 15 June 2017 в 18:27

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

import inspect
def bar():
    print "My name is", inspect.stack()[0][3]
8
ответ дан Bjorn 18 August 2018 в 07:49
поделиться

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

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>
12
ответ дан cad106uk 18 August 2018 в 07:49
поделиться
  • 1
    Как декоратор noob, мне интересно, есть ли способ получить доступ к func .__ name__ в контексте my_funky_name (чтобы я мог получить его значение и использовать его внутри my_funky_name) – cowbert 29 June 2017 в 21:57
  • 2
    Способ сделать это внутри функции my_funky_name - 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

4
ответ дан Christian Liin Hansen 18 August 2018 в 07:49
поделиться
functionNameAsString = sys._getframe().f_code.co_name

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

28
ответ дан CodeZombie 18 August 2018 в 07:49
поделиться
  • 1
    Такая же ситуация, как с .func_name. Стоит помнить, что имена классов и имена функций в Python - это одно, а переменные, относящиеся к ним, - это другое. – Kos 13 December 2012 в 13:48
  • 2
    Иногда вам может потребоваться Foo2() для печати Foo. Например: Foo2 = function_dict['Foo']; Foo2(). В этом случае Foo2 является указателем на функцию, возможно, для синтаксического анализа командной строки. – Harvey 1 June 2013 в 21:02
  • 3
    Какое значение скорости имеет это? – Robert C. Barth 20 February 2014 в 22:29
  • 4
    Скорейшее значение в отношении чего? Есть ли ситуация, когда вам нужно будет иметь эту информацию в сложной ситуации в реальном времени или что-то в этом роде? – bgporter 23 February 2014 в 17:27

Вы можете использовать декоратор:

def my_function(name=None):
    return name

def get_function_name(function):
    return function(name=function.__name__)

>>> get_function_name(my_function)
'my_function'
4
ответ дан Douglas Denhartog 18 August 2018 в 07:49
поделиться

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

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
107
ответ дан dwanderson 18 August 2018 в 07:49
поделиться
  • 1
    0.1python usec per loop означает нормальный 0.1 usec, или это какой-то другой (более pythonic) usec? – mbdevpl 8 July 2016 в 11:24
  • 2
    inspect.currentframe() кажется хорошим компромиссом между временем выполнения и использованием частных членов – FabienAndre 27 August 2016 в 09:44
  • 3
    @mbdevpl Мои номера равны 1,25 мс, 1,24 мс, 0,5%, 0,16% соответственно (непитонические :)) секунд (win7x64, python3.5.1) – Antony Hatchkins 5 January 2017 в 21:55
  • 4
    Просто так никто не думает, что @ mbdevpl сумасшедший :) - Я представил редактирование для выхода третьего запуска, так как это не имело никакого смысла. Не знаю, должен ли результат быть 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 ()]. ​​

10
ответ дан Gino 18 August 2018 в 07:49
поделиться
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

привет, я баре, папа

7
ответ дан Lee 18 August 2018 в 07:49
поделиться

Я использую свой подход, используемый для вызова супер с безопасностью внутри сценария множественного наследования (я положил весь код)

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__ в качестве текущего имени функции.

2
ответ дан Mel Viso Martinez 18 August 2018 в 07:49
поделиться
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
8
ответ дан nordborn 18 August 2018 в 07:49
поделиться

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

10
ответ дан Pierre Voisin 18 August 2018 в 07:49
поделиться
import inspect

def foo():
   print(inspect.stack()[0][3])
277
ответ дан Scott Martin 18 August 2018 в 07:49
поделиться
  • 1
    Это здорово, потому что вы также можете сделать [1][3], чтобы получить имя вызывающего абонента. – Kos 13 December 2012 в 13:47
  • 2
    Вы также можете использовать: print(inspect.currentframe().f_code.co_name) или получить имя вызывающего абонента: print(inspect.currentframe().f_back.f_code.co_name). Я думаю, что это должно быть быстрее, так как вы не извлекаете список всех фреймов стека, как это делает inspect.stack(). – Michael 23 February 2014 в 12:25
  • 3
    inspect.currentframe().f_back.f_code.co_name не работает с декорированным способом, тогда как inspect.stack()[0][3] делает ... – Dustin Wyatt 15 February 2016 в 19:08
  • 4
    Обратите внимание: inspect.stack () может нести тяжелые эксплуатационные издержки, поэтому используйте экономно! На моей руке мне потребовалось 240 мс (по какой-то причине) – gardarh 8 December 2016 в 13:59
  • 5
    – Tom Russell 26 July 2017 в 08:18
  • 6
    Это должен быть принятый ответ. – jasonleonhard 22 December 2017 в 02:45

Я поддерживаю эту удобную утилиту рядом:

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

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

myself()
17
ответ дан xxyzzy 18 August 2018 в 07:49
поделиться
  • 1
    Как это сделать с предложенной здесь альтернативой? «self = lambda: sys._getframe (). f_code.co_name & quot; не работает (выход «& lt; lambda & gt;»; я думаю, потому что результат определяется во время определения, а не позже во время вызова. – prismalytics.io 22 May 2017 в 22:42
  • 2
    @ prismalytics.io: Если вы называете себя (я ()) и не просто использую его значение (я), вы получите то, что ищете. – ijw 27 December 2017 в 20:56
  • 3
    Твой мой любимый ответ! – Nam G VU 20 July 2018 в 05:59
37
ответ дан Community 6 September 2018 в 21:10
поделиться
1
ответ дан nerdfever.com 6 September 2018 в 21:10
поделиться
2
ответ дан John Forbes 30 October 2018 в 02:25
поделиться
2
ответ дан nerdfever.com 30 October 2018 в 02:25
поделиться
39
ответ дан Community 30 October 2018 в 02:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: