Как получить имя функции в виде строки?

Как в Python получить имя функции в виде строки без вызова функции?

def my_function():
    pass

print get_function_name_as_string(my_function) # my_function is not in quotes

должен выводить "my_function".

Доступна ли такая функция в Python? Если нет, есть идеи о том, как реализовать get_function_name_as_string на Python?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
846
0
588 017
13
Перейти к ответу Данный вопрос помечен как решенный

Ответы 13

my_function.func_name

Есть и другие забавные свойства функций. Введите dir(func_name), чтобы перечислить их. func_name.func_code.co_code - это скомпилированная функция, хранящаяся в виде строки.

import dis
dis.dis(my_function)

отобразит код в удобочитаемом формате почти. :)

В чем разница между f .__ name__ и f.func_name?

Federico A. Ramponi 30.10.2008 22:43

Имена с двойным подчеркиванием традиционно считаются личными, хотя никогда не применяются. Поэтому лучше использовать func_name, даже если они могут быть одинаковыми.

Sam Corder 30.10.2008 23:11

Сэм: имена частные, __names особенные, есть концептуальная разница.

Matthew Trevor 31.10.2008 06:15

Если кто-то озадачен предыдущим ответом Мэтью, система комментариев интерпретировала некоторые двойные подчеркивания как код для жирного шрифта. Сообщение должно быть экранировано обратной кавычкой: __names__ - частные, __names - специальные.

gwideman 21.02.2014 01:34

@MatthewTrevor, у вас есть ссылка для получения дополнительной информации / подробностей?

rivy 12.03.2014 16:51

На самом деле, я думаю, что правильным является то, что _names являются частными (одинарное подчеркивание перед, просто соглашение), __names__ являются особенными (двойные подчеркивания перед и после). Не уверен, имеет ли двойное подчеркивание перед ним какое-либо значение, формально или как соглашение.

MestreLion 23.08.2014 12:48

@MestreLion Это называется искажение имени.

nyuszika7h 07.04.2015 14:59

@ nyuszika7h: правда, я забыл про фальсификацию имен. Поэтому я думаю, что лучший совет: используйте соглашение_name для «обычных» частных участников, поскольку __name может быть изменен в именах, а __name__ может быть «особенным» в зависимости от name, если только они не являются тем, что вы хотите, и вы знаете, что вы делает.

MestreLion 09.04.2015 06:47
func_name больше не существует в python3, поэтому вам нужно использовать func.__name__, если вам нужна совместимость.
Daenyth 07.04.2017 18:50
Ответ принят как подходящий
my_function.__name__

Использование __name__ является предпочтительным методом, поскольку он применяется единообразно. В отличие от func_name, он также работает со встроенными функциями:

>>> import time
>>> time.time.func_name
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: 'builtin_function_or_method' object has no attribute 'func_name'
>>> time.time.__name__ 
'time'

Также двойное подчеркивание указывает читателю, что это особый атрибут. В качестве бонуса классы и модули также имеют атрибут __name__, поэтому вам нужно запомнить только одно специальное имя.

Потому что в некоторых случаях вы получаете некоторый объект функции в качестве аргумента вашей функции, и вам нужно отображать / хранить / управлять именем этой функции. Возможно, вы создаете документацию, текст справки, историю действий и т. д. Так что нет, вы не всегда жестко кодируете имя функции.

mbargiel 26.07.2013 18:17

@mgargiel: Я хотел сказать следующее: предположим, у вас есть класс, который определяет 100 методов, где все методы являются только оболочками, которые вызывают частный метод, передавая имя самой оболочки. Примерно так: def wrapper(kwargs): super(ExtendedClass,self).call('wrapper', kwargs). У вас есть другой вариант: def wrapper(kwargs): super(ExtendedClass,self).call(sys._getframe().f_code.co_nam‌​e, kwargs). Так что ответ Альберта Вонпуппа кажется мне лучше.

Richard Gomes 30.08.2013 23:20

@RichardGomes Один ответ подходит для получения имени внутри самой функции, другой подходит для получения его из ссылки на функцию. Написанный вопрос ОП указывает на последнее.

Russell Borogove 31.08.2013 04:44

@RichardGomes На самом деле я пришел к этому вопросу в поисках решения этой проблемы. Проблема, которую я пытаюсь решить, - создать декоратор, который можно использовать для регистрации всех моих звонков.

ali-hussain 18.09.2013 23:36

Функции @RichardGomes - это первоклассные объекты, с ними может быть связано не только имя. Это не обязательно так, что f.__name__ == 'f'.

wim 14.03.2014 00:13

Я не вижу, чтобы это решение помогло, поскольку большинство людей будут использовать его только в том случае, если им нужно что-то общее, которое вы можете вызывать как метод много раз. Такой метод подойдет, если вы хотите отслеживать порядок выполнения функций. В приведенном выше решении говорится, что моя функция - foo, и вызывается foo._name__, а затем устанавливается имя переменной. С таким же успехом вы можете просто установить строку со значением foo. Вызов _getframe (), описанный ниже как другое решение, работает внутри нескольких функций внутри одного класса! именно то, что мне нужно.

Eamonn Kenny 04.12.2017 14:40

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

jonathan 20.04.2018 20:49

@RichardGomes Мой вариант использования - отладка функции функционального программирования. У меня есть функция, которая принимает функцию в качестве аргумента, и я хочу зарегистрировать имя переданной функции.

DVL 23.08.2019 22:52

Чтобы получить имя текущей функции или метода изнутри, рассмотрите:

import inspect

this_function_name = inspect.currentframe().f_code.co_name

sys._getframe также работает вместо inspect.currentframe, хотя последний избегает доступа к частной функции.

Чтобы вместо этого получить имя вызывающей функции, рассмотрите f_back как inspect.currentframe().f_back.f_code.co_name.


Если также используется mypy, он может жаловаться, что:

error: Item "None" of "Optional[FrameType]" has no attribute "f_code"

Чтобы подавить указанную выше ошибку, примите во внимание:

import inspect
import types
from typing import cast

this_function_name = cast(types.FrameType, inspect.currentframe()).f_code.co_name

+1: Это тот ответ, который я хотел бы увидеть. Другие ответы предполагают, что вызывающий уже знает имя функции, что является нонсенсом в контексте этого вопроса.

Richard Gomes 11.07.2013 20:43

Ричард: нет, это не так. ВЫ предполагаете, что вызываете имя или func_name для своей функции непосредственно в той же области, в которой она была определена, что очень часто не так. Имейте в виду, что функции являются объектами - они могут быть переданы в качестве аргументов другим функциям, сохранены в списках / dicts для последующего поиска или выполнения и т. д.

mbargiel 26.07.2013 18:24

@paulus_almighty, копаться в фреймах стека мне не кажется абстрактным! На самом деле это своего рода противоположность абстрактному. См. Примечание детали реализации в документации. Не все реализации Python будут включать sys._getframe - он напрямую связан с внутренними компонентами CPython.

senderle 31.01.2016 17:42

Это работает только внутри функции, но в вопросе указано, что функция не должна вызываться.

user2357112 supports Monica 29.03.2016 03:02

Если вы хотите обернуть свою функцию чем-то более удобным и легко запоминающимся, вам нужно получить кадр 1, например sys._getframe(1).f_code.co_name, поэтому вы можете определить функцию, например get_func_name(), и ожидать получения желаемого имени функции, которая вызвала.

m3nda 04.01.2017 13:39

@Igor, sys._getframe(), получает n фреймов, sys._getframe(1) берет фрейм "одного глубокого уровня" из списка / стека. Итак, если вы заключите вызов между классом-> функцией-> функцией, вам нужно будет передать количество функций / классов, которые вызвали его. Это немного странно, но просто. В одиночном и прямом вызове выполнение sys._getframe() означает sys._getframe(0), и, поскольку об этом явно не сказано, вы не можете магическим образом угадать, что вы можете передавать числа. Пожалуйста.

m3nda 16.02.2017 06:30

Не гарантируется, что sys._getframe() будет доступен во всех реализациях Python (см. исх.), вы можете использовать модуль traceback, чтобы сделать то же самое, например.

import traceback
def who_am_i():
   stack = traceback.extract_stack()
   filename, codeline, funcName, text = stack[-2]

   return funcName

Вызов stack[-1] вернет сведения о текущем процессе.

Извините, если sys._getframe() не определен, значит, traceback.extract_stack также не работает. Последний обеспечивает грубую надстройку функциональности первого; вы не можете ожидать увидеть одно без другого. Фактически, в IronPython 2.7 extract_stack() всегда возвращает []. -1

SingleNegationElimination 31.08.2013 05:06

Эта функция вернет имя функции вызывающего.

def func_name():
    import traceback
    return traceback.extract_stack(None, 2)[0][2]

Это похоже на ответ Альберта Вонпуппа с дружественной оберткой.

У меня был «<модуль>» в индексе [2], но сработало следующее: traceback.extract_stack (None, 2) [0] [- 1]

emmagras 18.10.2014 18:49

для меня это не работает, но работает: traceback.extract_stack () [- 1] [2]

mike01010 22.11.2014 06:54

Это сработает, если изменить первый индекс на 1, вы, ребята, должны научиться отлаживать, прежде чем комментировать ... traceback.extract_stack (None, 2) [1] [2]

Jcc.Sanabria 19.12.2018 21:35

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

import inspect
import logging
import traceback

def get_function_name():
    return traceback.extract_stack(None, 2)[0][2]

def get_function_parameters_and_values():
    frame = inspect.currentframe().f_back
    args, _, _, values = inspect.getargvalues(frame)
    return ([(i, values[i]) for i in args])

def my_func(a, b, c=None):
    logging.info('Running ' + get_function_name() + '(' + str(get_function_parameters_and_values()) +')')
    pass

logger = logging.getLogger()
handler = logging.StreamHandler()
formatter = logging.Formatter(
    '%(asctime)s [%(levelname)s] -> %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.INFO)

my_func(1, 3) # 2016-03-25 17:16:06,927 [INFO] -> Running my_func([('a', 1), ('b', 3), ('c', None)])

Мне нравится использовать декоратор функций. Я добавил класс, который также умножает время функции. Предположим, что gLog - это стандартный логгер Python:

class EnterExitLog():
    def __init__(self, funcName):
        self.funcName = funcName

    def __enter__(self):
        gLog.debug('Started: %s' % self.funcName)
        self.init_time = datetime.datetime.now()
        return self

    def __exit__(self, type, value, tb):
        gLog.debug('Finished: %s in: %s seconds' % (self.funcName, datetime.datetime.now() - self.init_time))

def func_timer_decorator(func):
    def func_wrapper(*args, **kwargs):
        with EnterExitLog(func.__name__):
            return func(*args, **kwargs)

    return func_wrapper

так что теперь все, что вам нужно сделать со своей функцией, это украсить ее и вуаля

@func_timer_decorator
def my_func():

Если вас тоже интересуют методы классов, в Python 3.3+ есть __qualname__ в дополнение к __name__.

def my_function():
    pass

class MyClass(object):
    def method(self):
        pass

print(my_function.__name__)         # gives "my_function"
print(MyClass.method.__name__)      # gives "method"

print(my_function.__qualname__)     # gives "my_function"
print(MyClass.method.__qualname__)  # gives "MyClass.method"

Если у метода есть декоратор @property, это не сработает, каким образом получить доступ к имени в этом экземпляре?

dusiod 28.11.2020 21:13

@dusiod, похоже, вы можете получить имя / qualname из геттера свойства (который вы создаете с помощью декоратора @property): MyClass.prop.fget.__qualname__ дает MyClass.prop.

lapis 30.11.2020 16:59

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

def function1():
    print "function1"

def function2():
    print "function2"

def function3():
    print "function3"
print function1.__name__

вывод будет function1

Теперь предположим, что у вас есть эти функции в списке

a = [function1 , function2 , funciton3]

чтобы получить имя функции

for i in a:
    print i.__name__

вывод будет

function1
функция2
функция3

import inspect

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

где

  • stack()[0] - это звонящий

  • stack()[3] - это строковое имя метода

Легко и просто. stack()[0] всегда будет вызывающим, [3] - строковым именем метода.

kontur 28.10.2019 16:04

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

def debug(func=None):
    def wrapper(*args, **kwargs):
        try:
            function_name = func.__func__.__qualname__
        except:
            function_name = func.__qualname__
        return func(*args, **kwargs, function_name=function_name)
    return wrapper

@debug
def my_function(**kwargs):
    print(kwargs)

my_function()

Выход:

{'function_name': 'my_function'}

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

spareTimeCoder 14.04.2020 22:32

Пытаться

import sys
fn_name = sys._getframe().f_code.co_name

дальнейшая ссылка https://www.oreilly.com/library/view/python-cookbook/0596001673/ch14s08.html

import inspect

def my_first_function():
    func_name = inspect.stack()[0][3]
    print(func_name)  # my_first_function

или же:

import sys

def my_second_function():
    func_name = sys._getframe().f_code.co_name
    print(func_name)  # my_second_function

Другие вопросы по теме