← Назад
Декоратор это как обертка на конфете - есть некоторый код, который может выполниться до и/или после работы функции.
def my_decorator(func):
    def wrapper():
        print('код, который выполняется до функции')
        func()
        print('код, который выполняется после работы функции')
    return wrapper
@my_decorator
def some_function():
    print('работает функция, которую мы задекорировали')
some_function()
# код, который выполняется до функции
# работает функция, которую мы задекорировали
# код, который выполняется после работы функции
def simple_decorator(func):
    def inner():
        print('Начало работы декоратора...')
        func()
        print('Декоратор отработал!')
    return inner
def print_hi():
    print('Привет, я - функция, которую задекорировали!')
print_hi = simple_decorator(print_hi)
print_hi()
# Начало работы декоратора...
# Привет, я - функция, которую задекорировали!
# Декоратор отработал!
def decorate_func_with_params(func):
    def inner(*args, **kwargs):
        print(f'Декорируем функцию с параметрами: {args}, {kwargs}')
        func(*args, **kwargs)
        print('Все прошло успешно!')
    return inner
@decorate_func_with_params
def adder(*nums):
    print(sum(nums))
adder(1)
adder(2, 7, 3)
adder(0, 33, 4, 10, 0)
# Декорируем функцию с параметрами: (1,), {}
# 1
# Все прошло успешно!
# Декорируем функцию с параметрами: (2, 7, 3), {}
# 12
# Все прошло успешно!
# Декорируем функцию с параметрами: (0, 33, 4, 10, 0), {}
# 47
# Все прошло успешно!
def repeater(num_of_repeats=1):
    def outer_decorator(func):
        def inner_decorator(*args, **kwargs):
            if num_of_repeats > 0:
                for _ in range(num_of_repeats):
                    print(func(*args, **kwargs))
            else:
                print(func(*args, **kwargs))
        return inner_decorator
    return outer_decorator
@repeater(3)
def print_text(message):
    return f'Вам сообщение: {message}'
print_text('Просыпайся!')
# Вам сообщение: Просыпайся!
# Вам сообщение: Просыпайся!
# Вам сообщение: Просыпайся!
При помощи метода __call__() экземпляры классов можно делать вызываемыми, что позволяет декорировать функции.
info_func() является экземпляром класса Numerator, поэтому счетчик при каждом новом вызове будет увеличиваться.
class Numerator:
    def __init__(self, func):
        self.func = func
        self.counts = 0
    def __call__(self, *args, **kwargs):
        self.counts += 1
        print(self.counts)
        return self.func(*args, **kwargs)
@Numerator
def info_func(*args, **kwargs):
    return args, kwargs
print(info_func(2, 3, p=100))
print(info_func(q=10))
print(info_func())
# 1
# ((2, 3), {'p': 100})
# 2
# ((), {'q': 10})
# 3
# ((), {})
class decorator(object):
    def __init__(self, f):
        print("inside decorator.__init__()")
        f()  # Prove that function definition has completed
    def __call__(self):
        print("inside decorator.__call__()")
@decorator
def function():
    print("inside function()")
print("Finished decorating function()")
function()
# inside decorator.__init__()
# inside function()
# Finished decorating function()
# inside decorator.__call__()
import asyncio
import sys
import uvloop
from functools import wraps
def do_n_times(n=2):
    # this returns a function that _actually_ gets passed the wrapped method.
    def wrapper(func):
        @wraps(func)
        async def wrapper_do_n_times():
            for _ in range(n - 1):
                await func()
            return await func()
        return wrapper_do_n_times
    return wrapper
@do_n_times(n=4)
async def print_me():
    print("me")
if sys.version_info >= (3, 11):
    with asyncio.Runner(loop_factory=uvloop.new_event_loop) as runner:
        runner.run(print_me())
else:
    uvloop.install()
    asyncio.run(print_me())
← Назад