Python Декораторы: Добавление Сверхсил к Вашим Функциям

Привет, стремящиеся к мастерству в Python! Сегодня мы погружаемся в увлекательный мир Python декораторов. Представьте декораторы как магические обертки, которые могут улучшить ваши функции сверхсилами. Волнующе, правда? Давайте отправимся в эту путешествие вместе!

Python - Decorators

Что Такое Декораторы?

Представьте, что у вас есть прекрасно упакованный подарок. Упаковка не изменяет сам подарок, но делает его выглядеть лучше, верно? Вот что и делают декораторы с вашими функциями в Python. Они оборачивают ваши функции, добавляя дополнительную функциональность, не изменяя при этом саму оригинальную функцию.

Начнем с простого примера:

def мой_декоратор(func):
def обертка():
print("Что-то происходит перед вызовом функции.")
func()
print("Что-то происходит после вызова функции.")
return обертка

@мой_декоратор
def скажи_привет():
print("Привет!")

скажи_привет()

Если вы выполните этот код, вы увидите:

Что-то происходит перед вызовом функции.
Привет!
Что-то происходит после вызова функции.

Разберем это:

  1. Мы определяем декоратор функции мой_декоратор, который принимает функцию в качестве аргумента.
  2. Внутри мой_декоратор, мы определяем функцию обертка, которая добавляет некоторое поведение до и после вызова оригинальной функции.
  3. Мы используем синтаксис @мой_декоратор, чтобы применить наш декоратор к функции скажи_привет.
  4. Когда мы вызываем скажи_привет(), на самом деле мы вызываем обернутую версию функции.

Ни что себе! Мы только что добавили некоторое дополнительное поведение к нашей функции скажи_привет, не изменяя ее код!

Декораторы с Аргументами

Но подождите, еще больше! Что если наша функция принимает аргументы? Нет проблем! Мы можем изменить наш декоратор, чтобы обрабатывать это:

def мой_декоратор(func):
def обертка(*args, **kwargs):
print("Перед вызовом функции.")
result = func(*args, **kwargs)
print("После вызова функции.")
return result
return обертка

@мой_декоратор
def сложить(a, b):
return a + b

print(сложить(3, 5))

Это выведет:

Перед вызовом функции.
После вызова функции.
8

Здесь *args и **kwargs позволяют нашему декоратору работать с любым количеством позиционных и именованных аргументов.

Встроенные Декораторы

Python приходит с некоторыми встроенными декораторами, которые чрезвычайно полезны. Давайте их рассмотрим!

Декоратор @classmethod

Декоратор @classmethod используется для определения методов, которые работают на самом классе, а не на экземплярах класса.

class Пицца:
def __init__(self, ингредиенты):
self.ингредиенты = ингредиенты

@classmethod
def маргарита(cls):
return cls(['моцарелла', 'томаты'])

@classmethod
def просиutto(cls):
return cls(['моцарелла', 'томаты', 'ветчина'])

print(Пицца.маргарита().ингредиенты)
print(Пицца.просиutto().ингредиенты)

Это выведет:

['моцарелла', 'томаты']
['моцарелла', 'томаты', 'ветчина']

Здесь маргарита и просиutto являются классовыми методами, которые создают и возвращают новые экземпляры Пиццы с предопределенными ингредиентами.

Декоратор @staticmethod

Статические методы — это методы, которые не работают ни на экземпляре, ни на классе. Это просто обычные функции, которые случайно находятся внутри класса.

class Математика:
@staticmethod
def сложить(a, b):
return a + b

print(Математика.сложить(5, 10))

Это выведет:

15

Декоратор @property

Декоратор @property позволяет определять методы, которые можно доступить как атрибуты.

class Круг:
def __init__(self, радиус):
self._радиус = радиус

@property
def радиус(self):
return self._радиус

@property
def площадь(self):
return 3.14 * self._радиус ** 2

c = Круг(5)
print(c.радиус)
print(c.площадь)

Это выведет:

5
78.5

Здесь мы можем доступить радиус и площадь, как если бы они были атрибутами, но на самом деле они являются методами.

Декоратор @functools.wraps

Этот декоратор используется для сохранения метаданных оригинальной функции при создании декораторов.

from functools import wraps

def мой_декоратор(func):
@wraps(func)
def обертка(*args, **kwargs):
"""Это обертывающая функция"""
return func(*args, **kwargs)
return обертка

@мой_декоратор
def моя_функция():
"""Это моя функция"""
pass

print(моя_функция.__name__)
print(моя_функция.__doc__)

Это выведет:

моя_функция
Это моя функция

Без @wraps, имя функции и документация были бы теми, что у обертывающей функции.

Заключение

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

Помните, ключ к владению декораторами — это практика. Попробуйте создать свои собственные декораторы и применить их к различным функциям. Скоро вы будете оборачивать ваши функции сверхсилами как профи!

Вот таблица, подводящая итог декораторов, которые мы рассмотрели:

Декоратор Назначение
@classmethod Определять методы, которые работают на самом классе
@staticmethod Определять методы, которые не работают ни на экземпляре, ни на классе
@property Определять методы, которые можно доступить как атрибуты
@functools.wraps Сохранять метаданные оригинальной функции в декораторах

Счастливого кодирования, и пусть ваши функции всегда украшены красиво!

Credits: Image by storyset