Получение имени вызывающего метода в Python без изменений

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

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

Python
Скопировать код
import inspect

def вызываемая_функция():
    # Извлечение названия вызывающей функции
    print(f"Вызывающая: {inspect.currentframe().f_back.f_code.co_name}")

def вызывающая():
    # Осуществляем вызов
    вызываемая_функция()

вызывающая()

В итоге мы получаем следующий результат: Вызывающая: вызывающая. Это приятное и простое решение, типичное для Python.

Кинга Идем в IT: пошаговый план для смены профессии

Альтернативы и подводные камни

Если модуль inspect не устраивает, можно рассмотреть использование функции sys._getframe(), однако с внимательностью:

Python
Скопировать код
import sys

def вызываемая_функция():
    # Выясняем имя вызывающей функции
    print(f"Вызывающая: {sys._getframe(1).f_code.co_name}")

def вызывающая():
    # Здесь происходит вызов
    вызываемая_функция()

вызывающая()

Результат будет таким же, однако, sys._getframe() — это недокументированная и внутренняя функция, использование её в продакшене может быть сопоставимо с выпуском Джокера на свободу в Готэм.

Состязание в производительности

Помните, что использование inspect.stack() может существенно увеличить нагрузку на производительность системы:

Python
Скопировать код
def вызываемая_функция():
    # Можем ли мы быть быстрее?
    имя_вызывающей = inspect.stack()[1][3]
    # ... продолжение текста ...

Более низкая нагрузка и высокая производительность достигаются при помощи:

Python
Скопировать код
def вызываемая_функция():
    # Мгновенное получение имени вызывающей функции
    имя_вызывающей = inspect.currentframe().f_back.f_code.co_name
    # ... здесь продолжается статья ...

Для отладки стоит использовать inspect.stack(), но в продакшина лучше отдать предпочтение более быстрой currentframe().

Особенности работы с памятью: утечки фреймов

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

Ваш путеводитель по стеку вызовов

Изучение стека вызовов может обеспечить важную информацию:

Python
Скопировать код
import inspect

def вызываемая_функция():
    # Пропускаем текущий выполняемый контекст
    информация_вызывающей = inspect.stack()[1]
    # Извлекаем необходимые данные
    название_функции, название_файла, номек_строки, назание_метода, контекст_кода, индекс = информация_вызывающей
    print(f"Функция '{название_метода}' была вызвана в строке {номек_строки} из файла '{название_файла}'.")

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

Визуализация

Представьте, что прослеживание названия вызывающей функции – это что-то вроде расследования в детективной истории.

Среди слоёв кода прячется уклончивый метод:

Python
Скопировать код
def вызываемая_функция():
    ...

Детектив достаёт лупу:

Python
Скопировать код
import inspect
def вызываемая_функция():
    имя_вызывающего = inspect.stack()[1].function
    return f"Меня вызвала... {имя_вызывающего}!"

И тайна всё ближе к разгадке:

"Мы нашли имя уклончивой функции — 📜 call_me_maybe!"

Путь вызывающей функции становится яснен:

Стек вызовов:

  1. 🌟main_function🌟
  2. helper_function
  3. 👀call_me_maybe👀

След за следом, солнце садится, тайна разгадана! 🎯

Варианты: разные контексты

Классы и модули

С методами классов и модулями всё становится слегка сложнее:

Python
Скопировать код
class MyClass:
    def метод_один(self):
        # Запускаем метод_два
        self.метод_два()
    
    def метод_два(self):
        print(f"Меня вызвал: {inspect.stack()[1][3]}")

экземпляр = MyClass()
экземпляр.метод_один()

Пример демонстрирует, что метод_один инициирует вызов метод_два.

Безымянные вызовы

С безымянными функциями, такими как лямбды:

Python
Скопировать код
(lambda: вызываемая_функция())()

inspect.stack()[1][3] вернёт '<lambda>', обеспечивая возможность отследить даже анонимные вызовы.

Вызовы из главного блока

Многим функциям необходимо знать, были ли они вызваны из главного блока:

Python
Скопировать код
if __name__ == '__main__':
    def вызываемая_функция():
        print("Функция вызвана из главного блока вызовов.")

    вызываемая_функция()

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

Полезные материалы

  1. inspect — Исследование живых объектов — Документация Python 3.12.2 — Детализированная информация о модуле inspect.
  2. 3. Модель данных — Документация Python 3.12.2 — Глубокий анализ фреймов и объектов в Python.
  3. Как пользоваться модулем logging — Документация Python 3.12.2 — Руководство по записи информации о вызовах в лог-файлы.
  4. traceback — Печать или извлечение трассировки стека — Документация Python 3.12.2 — Инструкция о трассировках для отладки.
  5. Понимание Python Traceback – Real Python — Описание трассировок стека от Real Python.
  6. Исключительные Исключения – Доклад на PyCon от Марио Корчеро — Обсуждение исключений и трассировок стека на конференции PyCon.
  7. Встроенные функции Python | Programiz — Описывается функция inspect.stack() на ресурсе Programiz.