Декораторы

Что такое декораторы

@kakayato_shnyaga - это декоратор.

Декоратор - это структурный паттерн проектирования, который позволяет динамически добавлять объектам новую функциональность, оборачивая их в полезные «обёртки». Подробнее можно посмотреть в книге по паттернам которая лежит в папке book.

В питоне есть особая синтаксическая конструкция позволяющая реализовывать этот паттерн. Выглядит она так:

@dekorator
def puk():
    print('puk')

Если вызвать данную функцию то результат может оказаться не таким как ты этого ожидаешь на первый взгляд. Так как декоратор может управлять твоей функцией/методом как ему вздумается.

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

def dekorator(func):
    def wrapper():
       print("before")
       func()
       print("after")
    return wrapper

Для чего это все? Чтобы писать меньше кода. Можно например дебажить в реальном времени какую-то конкретную функцию с помощью декоратора который логирует результат функции.

Вот так например:

def log_func_result(func):
    def wrapper(*args):
        result = func(*args)
        print("Результат функции:", result)
        return result
    return wrapper

@log_func_result
def calculate(x, y):
    return x * y

value = calculate(3, 7)

Декораторы которые встречаются в реальном коде

Python содержит несколько встроенных декораторов. Из всех этих декораторов, самыми популярными являются эти:

@classmethod @staticmethod @property

Также существуют декораторы в различных разделах стандартной библиотеки Python. Одним из примеров является functools.wraps.

@classmethod может быть вызван при помощи экземпляра класса, или напрямую, через собственный класс Python в качестве первого аргумента. В соответствии с документацией Python: он может быть вызван как в классе (например, C.f()), или в экземпляре (например, C().f()). Экземпляр игнорируется, за исключением его класса. Если метод класса вызван для выведенного класса, то объект выведенного класса передается в качестве подразумеваемого первого аргумента. Используется в основном для кастомных конструкторов, например, cls вместо явного “базового класс” позволит наследнику порождать именно наследника а не родителя.

@staticmethod — это просто функция внутри класса. Можно вызвать как с инициализацией класса так и без создания объекта. Обычно это применяется в тех случаях, когда у вас есть функция, которая, по вашему убеждению, имеет связь с классом но при этом слабо связанна с конкретным объектом. Является аналогом static методов в Java/C++.

@property позволит превратить метод класса в атрибут класса Полезно когда хочется сделать какое нибудь поле которое как то зависит от других полей.

Property

class Person(object):
    """"""
    def __init__(self, first_name, last_name):
        """Конструктор"""
        self.first_name = first_name
        self.last_name = last_name
    
    @property
    def full_name(self):
        """
        Возвращаем полное имя
        """
        return "%s %s" % (self.first_name, self.last_name)

В данном коде мы создали класс Person в котором есть имя и фамиля как поля класса и проперти полное имя.

person = Person("Mike", "Driscoll")
 
print(person.first_name) # Mike
print(person.full_name) # Mike Driscoll
 
person.full_name = "Jackalope"
# Подобное запрещено поэтому появится ошибка:
# Traceback (most recent call last):
#     File "<string>", line 1, in <fragment>
# AttributeError: can't set attribute

person.first_name = "Dan"
print(person.full_name) # Dan Driscoll