JavaRush /Курси /Модуль 1: Python Core /Вся потужність декораторів

Вся потужність декораторів

Модуль 1: Python Core
Рівень 8 , Лекція 5
Відкрита

6.1 Декоратори для методів класів

Декоратори також можуть використовуватися для методів класів. Важливо пам'ятати, що для методів класів необхідно правильно передавати аргументи self або cls.

Нюанси роботи класів ми з вами ще не проходили, але хотілося б, щоб ви знали, що така можливість у декораторів є.


def log_method_call(func):
    def wrapper(self, *args, **kwargs):
        print(f"Виклик методу {func.__name__}")
        return func(self, *args, **kwargs)

    return wrapper
        
class MyClass:
    @log_method_call
    def say_hello(self):
        print("Hello from MyClass!")
        
obj = MyClass()
obj.say_hello()

Пояснення

Декоратор (log_method_call): Цей декоратор приймає метод func і повертає нову функцію wrapper, яка виводить повідомлення перед викликом методу.

Метод класу з декоратором (say_hello): Метод say_hello обгорнутий декоратором log_method_call, що додає додаткову поведінку при його виклику.

Вивід:


Виклик методу say_hello
Hello from MyClass!

6.2 Декілька декораторів

Ви можете використовувати кілька декораторів для однієї функції, накладаючи їх один на одного. Декоратори застосовуються в порядку, зворотному їх оголошенню.


def decorator1(func):
    def wrapper():
        print("Декоратор 1")
        func()

    return wrapper
        
def decorator2(func):
    def wrapper():
        print("Декоратор 2")
        func()

    return wrapper
        
@decorator1
@decorator2
def say_hello():
    print("Hello!")
        
say_hello()

Пояснення

Декоратори (decorator1 і decorator2): Ці декоратори додають свої повідомлення перед викликом функції func.

Функція з декораторами (say_hello): Функція say_hello обгорнута обома декораторами. Спочатку застосовується decorator2, потім decorator1.

Вивід:


# Декоратор 1
# Декоратор 2
Hello!

6.3 Вбудовані декоратори

Python надає кілька вбудованих декораторів для стандартних задач, таких як статичні методи, методи класу та властивості.

@staticmethod

Декоратор @staticmethod використовується для створення статичного методу, який не потребує екземпляра класу для виклику.


class MyClass:
    @staticmethod
    def static_method():
        print("Це статичний метод.")
        
MyClass.static_method()

@classmethod

Декоратор @classmethod використовується для створення методу класу, який приймає клас (а не екземпляр) як перший аргумент.


class MyClass:
    @classmethod
    def class_method(cls):
        print(f"Це метод класу {cls.__name__}.")
        
MyClass.class_method()

@property

Декоратор @property використовується для створення геттерів, сеттерів і делетерів для атрибутів.


class MyClass:
    def __init__(self, value):
        self.hidden_value = value
        
    @property
    def value(self):
        return self.hidden_value
        
    @value.setter
    def value(self, new_value):
        self.hidden_value = new_value
        
obj = MyClass(10)
print(obj.value)  # Вивід: 10
obj.value = 20
print(obj.value)  # Вивід: 20

Це вбудовані декоратори, їх правильну роботу забезпечує сам інтерпретатор Python.

6.4 Приклади використання декораторів

Логування

Декоратори можуть бути використані для логування викликів функцій і методів.


def log_call(func):
    def wrapper(*args, **kwargs):
        print(f"Виклик функції {func.__name__} з аргументами {args} і {kwargs}")
        return func(*args, **kwargs)

    return wrapper
        
@log_call
def add(x, y):
    return x + y
        
print(add(2, 3))

Контроль доступу

Декоратори можуть бути використані для контролю доступу до функцій і методів.


def require_authentication(func):
    def wrapper(*args, **kwargs):
        if not args[0].is_authenticated:
            raise PermissionError("Користувач не аутентифікований.")
        return func(*args, **kwargs)
        
    return wrapper
        
class User:
    def __init__(self, is_authenticated):
        self.is_authenticated = is_authenticated
        
    @require_authentication
    def view_profile(self):
        print("Профіль користувача")
        
user = User(is_authenticated=True)
user.view_profile()  # Успішний виклик
        
user2 = User(is_authenticated=False)
user2.view_profile()  # PermissionError: Користувач не аутентифікований.

Кешування

Декоратори можуть бути використані для кешування результатів функції.


def cache(func):
    cached_results = {}

    def wrapper(*args):
        if args in cached_results:
            return cached_results[args]
        result = func(*args)
        cached_results[args] = result
        return result

    return wrapper

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

print(fib(35))
Коментарі (9)
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ
Євген Рівень 26
3 липня 2025
незрозуміло що означає строка 'if not args[0].is_authenticated'
Ruslan D Рівень 50
3 липня 2025
Я не можу зрозуміти, як на другому місяці навчання може початківець розв’язувати такі задачі(((
Tony Рівень 79
2 липня 2025
Рішення задачі вимагає import time - якийй ми ще не проходили((( Як це вирішувати - в мене повний аут з розумінням декораторів ((((
Владислав Рівень 21
5 липня 2025
теж деф, декоратори дають дуже тяжко - задачі майже не піддають розумінню та виконанню (
negoda Рівень 31
10 серпня 2025
Из условия задачи мы уже знаем что нам понадобится этот модуль, идем в гугл и ищем как он работает, или на крайняк спрашиваем у ГПТчата. Доскональное понимание что такое декоратор и как он работает на интуитивном уровне прийдет позже, пока достаточно просто помнить что декоратор - это функция, с помощью которой мы можем менять свойства другой фукнции, не изменяя ее саму. Просто держа это в голове, и уже теперь концентрируясь не на том что такое декоратор, а на том как нам нужно его написать чтобы он делал то-то то-то, идем и стараемся придумать как это реализовать, зная тот минимум о том как декоратор вообще выглядит. Я когда жарю стейки не меряю температуру внутри мяса, я жарю его просто по интуиции и на глаз, мне просто достаточно знать что это стейк и того какого цвета он должно быть внутри, так же и здесь, мне не обязательно полностью под капотом понимать как это все работает, достаточно того что я знаю о том как строится и выглядит декоратор на околоинтуитивном уровне, и то что он должен делать в конечном итоге, а там потихоньку и вырисовывается логика декоратора. И когда ты сам напишешь несколько, то уже будешь гораздо лучше понимать как это делать.
Denis Рівень 14
16 червня 2025
Щось в мене не стикується вивід з поясненням. Спочатку вказаний декоратор_1 потім декоратор_2. В поясненні вказано, що декоратори використовуються в зворотньому порядку. Але на виводі порядок той самий в якому вони вказані. Вивод: Декоратор_1, Декоратор_2
Denis Рівень 14
16 червня 2025

def deco1(func):
    def wrapper(*args, **kwargs):
        print("deco1: до")
        result = func(*args, **kwargs)
        print("deco1: після")
        return result
    return wrapper

def deco2(func):
    def wrapper(*args, **kwargs):
        print("deco2: до")
        result = func(*args, **kwargs)
        print("deco2: після")
        return result
    return wrapper

@deco1
@deco2
def say_hi():
    print("Привіт!")

say_hi()

deco1: до
deco2: до
Привіт!
deco2: після
deco1: після
negoda Рівень 31
10 серпня 2025
Потому что это эквивалентно такой записи :

say_hi = deco1(deco2(say_hi))
Надеюсь понятна логика
Pavlo Kushnir Рівень 2
4 червня 2025
Що ж, з замиканням та декораторами я потрепив в глухий кут. І як вийти поки не розумію. Вже день витратив на розуміння.