Декораторы позволяют добавить дополнительное поведение к функции, не изменяя её исходный код.
Декоратор - это функция, которая принимает другую функцию в качестве входных данных и возвращает новую функцию.
🎯 Простой декоратор
Сначала определите декоратор, затем примените его с помощью `@имя_декоратора` над функцией.
Размещая @changecase непосредственно над определением функции, функция myfunction "декорируется" функцией changecase.
🔄 Множественные вызовы декоратора
Декоратор можно вызывать несколько раз. Просто разместите декоратор над функцией, которую хотите декорировать.
Пример
Использование декоратора @changecase на двух функциях:
📝 Аргументы в декорируемой функции
Функции, требующие аргументы, также могут быть декорированы - просто убедитесь, что передаёте аргументы в функцию-обёртку:
Пример
Декорирование функций с аргументами:
🌟 *args и **kwargs
Иногда декоратор не контролирует аргументы, передаваемые из декорируемой функции. Чтобы решить эту проблему, добавьте (*args, **kwargs) в функцию-обёртку - так она сможет принимать любое количество аргументов любого типа и передавать их в декорируемую функцию.
Пример
Защита функции с аргументами *args и **kwargs:
🎁 Декоратор с аргументами
Декораторы могут принимать собственные аргументы, добавляя ещё один уровень обёртки.
Пример
Фабрика декораторов, которая принимает аргумент и преобразует регистр на основе значения аргумента:
🎪 Множественные декораторы
Вы можете использовать несколько декораторов на одной функции.
Это делается путём размещения вызовов декораторов друг над другом.
Декораторы вызываются в обратном порядке от их указания.
Пример
Один декоратор для верхнего регистра и один для добавления приветствия:
Этот декоратор автоматически запоминает результаты вычислений, что особенно полезно для ресурсоёмких функций! 🎯
🛡️ Сохранение метаданных функции
Функции в Python содержат метаданные, к которым можно обратиться с помощью атрибутов `__name__` и `__doc__`.
Пример
Обычно имя функции можно получить с помощью атрибута `__name__`:
Но когда функция декорируется, метаданные оригинальной функции теряются. 😱
Пример
Попробуйте получить имя из декорированной функции, и вы не получите тот же результат:
Чтобы исправить это, в Python есть встроенная функция functools.wraps, которую можно использовать для сохранения оригинального имени функции и строки документации. 🎯
Пример
Импортируйте functools.wraps для сохранения оригинального имени функции и строки документации:
💡 Всегда используйте functools.wraps!
Это считается best practice при создании декораторов. Вот почему это важно:
Без @functools.wraps вы бы потеряли всю эту ценную информацию! 🎭✨
Ключевые преимущества использования `functools.wraps`:**
✅ Сохраняет оригинальное имя функции
✅ Сохраняет строку документации (`__doc__`)
✅ Сохраняет другие метаданные (модуль, квалифицированное имя и т.д.)
✅ Делает отладку значительно проще
✅ Считается best practice в Python сообществе