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))
Коментарі (11)
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ
Євген Рівень 24
16 серпня 2025
Стосовно того, що раніше не вивчали модуль time, то в цілому це так, але в в лекції "Генератори на практиці" в самому кінці згадувалась час виконання генератора та списку. Тому рекомендую опиратися саме цю лекцію. А декоратори взагалі цікава тема, бо тут використовується принцип closure (тобто замикань), як я розумію. Особисто для мене головне було запам'ятати, що це просто хороший спосіб додати нову логіку до вже існуючої, не ламаючи останньої. Вже як ти будеш це реалізовувати - це, звісно, інше питання. Просто вся складність, що, наприклад, зараз згадувалась тема класів, яку ще не проходили, тому розуміння цього матеріалу було не таке очевидне, як хотілося б.
23 липня 2025
Сам поплавився на цих декораторах. Але потім подивився короткі пояснення на ютуб, що таке декоратор і як використовується. Прояснилось.
Євген Рівень 26
3 липня 2025
незрозуміло що означає строка 'if not args[0].is_authenticated'
Ruslan D Рівень 37
3 липня 2025
Я не можу зрозуміти, як на другому місяці навчання може початківець розв’язувати такі задачі(((
Tony Рівень 37
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 Рівень 26
4 червня 2025
Що ж, з замиканням та декораторами я потрепив в глухий кут. І як вийти поки не розумію. Вже день витратив на розуміння.