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

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

Відкрита

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))
2
Задача
Модуль 1: Python Core,  8 рівень,  5 лекція
Недоступна
Множина декораторів.
Множина декораторів.
2
Задача
Модуль 1: Python Core,  8 рівень,  5 лекція
Недоступна
Тривалість роботи.
Тривалість роботи.
Коментарі (9)
  • популярні
  • нові
  • старі
Щоб залишити коментар, потрібно ввійти в систему
Євген
Рівень 26
3 липня 2025, 20:46
незрозуміло що означає строка 'if not args[0].is_authenticated'
Ruslan D
Рівень 50
3 липня 2025, 09:39
Я не можу зрозуміти, як на другому місяці навчання може початківець розв’язувати такі задачі(((
Tony
Рівень 79
2 липня 2025, 19:07
Рішення задачі вимагає import time - якийй ми ще не проходили((( Як це вирішувати - в мене повний аут з розумінням декораторів ((((
Владислав
Рівень 21
5 липня 2025, 10:51
теж деф, декоратори дають дуже тяжко - задачі майже не піддають розумінню та виконанню (
negoda @poviranacze - Telegram в Python Intern (Train
10 серпня 2025, 09:56
Из условия задачи мы уже знаем что нам понадобится этот модуль, идем в гугл и ищем как он работает, или на крайняк спрашиваем у ГПТчата. Доскональное понимание что такое декоратор и как он работает на интуитивном уровне прийдет позже, пока достаточно просто помнить что декоратор - это функция, с помощью которой мы можем менять свойства другой фукнции, не изменяя ее саму. Просто держа это в голове, и уже теперь концентрируясь не на том что такое декоратор, а на том как нам нужно его написать чтобы он делал то-то то-то, идем и стараемся придумать как это реализовать, зная тот минимум о том как декоратор вообще выглядит. Я когда жарю стейки не меряю температуру внутри мяса, я жарю его просто по интуиции и на глаз, мне просто достаточно знать что это стейк и того какого цвета он должно быть внутри, так же и здесь, мне не обязательно полностью под капотом понимать как это все работает, достаточно того что я знаю о том как строится и выглядит декоратор на околоинтуитивном уровне, и то что он должен делать в конечном итоге, а там потихоньку и вырисовывается логика декоратора. И когда ты сам напишешь несколько, то уже будешь гораздо лучше понимать как это делать.
Denis
Рівень 14
16 червня 2025, 06:09
Щось в мене не стикується вивід з поясненням. Спочатку вказаний декоратор_1 потім декоратор_2. В поясненні вказано, що декоратори використовуються в зворотньому порядку. Але на виводі порядок той самий в якому вони вказані. Вивод: Декоратор_1, Декоратор_2
Denis
Рівень 14
16 червня 2025, 06:11
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 @poviranacze - Telegram в Python Intern (Train
10 серпня 2025, 09:22
Потому что это эквивалентно такой записи :
say_hi = deco1(deco2(say_hi))
Надеюсь понятна логика
Pavlo Kushnir Працює в друкарня
4 червня 2025, 00:37
Що ж, з замиканням та декораторами я потрепив в глухий кут. І як вийти поки не розумію. Вже день витратив на розуміння.