Имя функции в Python: атрибут __name__ и его применение

Раздел: Основы Python -> Функции

Основное: атрибут __name__ у функций

Каждая функция в Python является объектом и имеет встроенный атрибут __name__, который хранит строковое имя функции, заданное при определении. Этот атрибут автоматически создаётся интерпретатором и позволяет получить имя функции во время выполнения. Например, для функции, объявленной как def hello(): pass, значение hello.__name__ будет равно 'hello'.

def hello():
    pass

print(hello.__name__)

аргументы print python (аргументы функции print в python)

hello

Python 3 аргументы (аргументы в python 3)

Атрибут __name__ особенно полезен в декораторах, логировании и отладке - он помогает идентифицировать, какая именно функция выполняется, не заглядывая в её тело.

Как изменить имя функции после её создания?

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

def original():
    pass

print(original.__name__)
original.__name__ = 'renamed'
print(original.__name__)

аргумент параметр python (аргументы и параметры в python)

original
renamed

аргумент класса python (аргументы класса python)

Проблема: Изменение __name__ может затруднить отладку, так как трассировка стека выводит текущее имя. Типичная ошибка - попытка переименовать встроенную функцию, что вызовет исключение AttributeError (атрибут только для чтения у встроенных функций C).

Как использовать __name__ в декораторах для сохранения имени?

При создании декоратора без обёртки через functools.wraps имя декорируемой функции теряется - оно заменяется именем внутренней функции. Чтобы этого избежать, применяют декоратор @wraps из модуля functools, который копирует атрибут __name__ (и другие) из исходной функции.

from functools import wraps

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"Вызвана функция {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def example():
    pass

print(example.__name__)

Python аргументы строки (аргументы строки в python (командная строка))

Вызвана функция example
example

аргумент метода python (аргументы метода python)

Типичная ошибка: Если забыть @wraps, то example.__name__ будет 'wrapper', что ломает логирование и интроспекцию.

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

Изнутри функции её имя доступно через __name__ самой функции (например, используя глобальное имя функции, но лучше передать явно). Однако внутри тела функции нельзя обратиться к __name__ напрямую как к локальной переменной - нужно использовать sys._getframe().f_code.co_name или просто ссылку на функцию.

import sys

def test():
    # Вариант 1: прямое обращение к __name__ (не сработает, так как test ещё не определена)
    # print(__name__) # NameError
    # Вариант 2: через sys
    print(sys._getframe().f_code.co_name)

test()

Python args (аргументы в python)

test

именованные аргументы функции python (именованные аргументы функции python)

Проблема: Использование sys._getframe() не рекомендуется в продакшене из-за затрат производительности и зависимости от реализации. Лучше передавать имя как аргумент или использовать декоратор.

Как проверить, является ли объект функцией и получить её имя?

Для проверки типа объекта на функцию используется callable() или inspect.isfunction(). После этого можно безопасно получить __name__, если объект является функцией.

import inspect

def my_func():
    pass

lambda_func = lambda: None

print(inspect.isfunction(my_func))
print(inspect.isfunction(lambda_func))
print(my_func.__name__)
print(lambda_func.__name__)

именованные аргументы python (именованные аргументы python)

True
True
my_func
<lambda>

Типичная ошибка: У лямбда-функций __name__ всегда '<lambda>', что может быть неинформативно. Для лямбд рекомендуется задавать имя через присваивание переменной, но __name__ не изменится.

- Python передать аргументы (передача аргументов в python)
- переменное количество аргументов python (переменное количество аргументов python)
- Python принять аргументы (приём аргументов в python)

Расширенные примеры работы с __name__

Пример
# Пример 1: создание функций с динамическим именем через type()
def create_function(name, body_code):
    # body_code - строка с телом функции
    exec(body_code)
    # создаём объект функции с заданным именем
    func = type(name, (object,), {}).__init__
    return func

# Примечание: на практике для динамического создания функций лучше использовать exec или compile

def make_adder(n):
    def adder(x):
        return x + n
    adder.__name__ = f'adder_{n}'
    return adder

add5 = make_adder(5)
print(add5.__name__)
print(add5(10))
adder_5
15
Пример
# Пример 2: использование __name__ для логирования вызовов
def logged(func):
    def wrapper(*args, **kwargs):
        print(f"[LOG] Вызов {func.__name__} с args={args} kwargs={kwargs}")
        result = func(*args, **kwargs)
        print(f"[LOG] {func.__name__} вернула {result}")
        return result
    return wrapper

@logged
def multiply(a, b):
    return a * b

multiply(3, 4)
[LOG] Вызов multiply с args=(3, 4) kwargs={}
[LOG] multiply вернула 12
Пример
# Пример 3: кэширование результатов с учётом имени функции (декоратор lru_cache имитация)
def cache_result(func):
    cache = {}
    def wrapper(*args):
        key = (func.__name__,) + args
        if key not in cache:
            cache[key] = func(*args)
        return cache[key]
    wrapper.__name__ = func.__name__
    return wrapper

@cache_result
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

print(fib(10))
55
Пример
# Пример 4: интроспекция цепочки декораторов
from functools import wraps

def decorator1(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

def decorator2(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

@decorator1
@decorator2
def final_func():
    return "done"

print(final_func.__name__)
print(final_func.__wrapped__.__name__)
final_func
delegator? (зависит от реализации wraps)
Пример
# Пример 5: получение имени из стека вызовов (не рекомендуется для продакшена)
import traceback

def whoami():
    stack = traceback.extract_stack()
    # последний элемент стека - текущий вызов
    print(stack[-2].name)  # имя функции, вызвавшей whoami

def test_call():
    whoami()

test_call()
test_call

Функция с именем name в Python - comments

En
функция name python (python)