from functools import wraps import time ''' Такой декоратор работать не будет ''' ''' def html_tag(func, name_tag='h1'): def inner(*args, **kwargs): result = func(*args, **kwargs) return f'<{name_tag}>{result}' return inner ''' ''' def decorator_factory(a, b): print('Запуск функции создания декоратора') def decorator(fn): print('Запуск декоратора') def wrapper(*args, **kwargs): print('Запуск функции wrapper') print('Переданные аргументы: ', a, b) return fn(*args, **kwargs) return wrapper return decorator ''' ''' Можно раскрыть следующей записью decorator = decorator_factory() # получаем декоратор из decorator_factory original_func = decorator(original_func) # декорируем Или есть еще вариант original_func = decorator_facotry()(original_func) ''' ''' @decorator_factory(10, 20) # Обратите внимание на оператор вызова def original_func(): print('Запуск оригинальной функции') ''' ''' Рабочий вариант декоратора ''' def html_tag(name_tag='h1'): def decorator(func): @wraps(func) def inner(*args, **kwargs): result = func(*args, **kwargs) return f'<{name_tag}>{result}' return inner return decorator @html_tag(name_tag='table') @html_tag('td') @html_tag() @html_tag('p') def say_hello_to(name, surname): return f'Hello {name} {surname}' def cached_with_expiry(expiry_time): def decorator(original_function): cache = {} # словарь для хранения кеша def wrapper(*args, **kwargs): key = (*args, *kwargs.items()) if key in cache: cached_value, cached_timestamp = cache[key] if time.time() - cached_timestamp < expiry_time: return f'[CACHED] - {cached_value}' result = original_function(*args, **kwargs) cache[key] = (result, time.time()) return result return wrapper return decorator @cached_with_expiry(expiry_time=5) def get_product(x, y): return x*y def multiply_result_by(n): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): result = func(*args, **kwargs) return n*result return wrapper return decorator def limit_query(n): def decorator(func): limit = n @wraps(func) def wrapper(*args, **kwargs): nonlocal limit if limit == 0: print(f'Лимит вызовов закончен, все {n} попытки израсходованы') return None else: limit -= 1 return func(*args, **kwargs) return wrapper return decorator def monkey_patching(arg='Monkey', kwarg='patching'): def decorator(func): @wraps(func) def wrapper(*_args, **_kwargs): patched_args = (arg, )*len(_args) patched_kwargs = {key:kwarg for key, _ in _kwargs.items()} return func(*patched_args, **patched_kwargs) return wrapper return decorator @monkey_patching(kwarg='Duper') def print_args_kwargs(*args, **kwargs): for i, value in enumerate(args): print(i, value) for k, v in sorted(kwargs.items()): print(f'{k} = {v}') def pass_arguments(*args_, **kwargs_): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): print(args_, kwargs_) return func(*args, **kwargs) return wrapper return decorator @pass_arguments(s='Когда', w='-', r='нибудь!') def concatenate(**kwargs): result = "" for arg in kwargs.values(): result += str(arg) return result def pass_arguments(*args_, **kwargs_): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): new_args = args + args_ new_kwargs = kwargs | kwargs_ return func(*new_args, **new_kwargs) return wrapper return decorator def convert_to(type_): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): return type_(func(*args, **kwargs)) return wrapper return decorator @convert_to(str) def add_values(a, b): return a + b ''' def validate_all_args_str(func): def wrapper(*args, **kwargs): if len([True for x in args if type(x) == str]) == len(args): return func(*args, **kwargs) else: print('Все аргументы должны быть строками') return wrapper ''' def validate_all_args(type_): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): if len([True for x in args if type(x) == type_]) == len(args): return func(*args, **kwargs) else: print(f'Все аргументы должны принадлежать типу {type_}') return wrapper return decorator @validate_all_args(set) def print_args_kwargs(*args, **kwargs): for i, value in enumerate(args): print(i, value) for k, v in sorted(kwargs.items()): print(f'{k} = {v}') def compose(*args_): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): result = func(*args, **kwargs) for f in args_: result = f(result) return result return wrapper return decorator def double_it(a): return a * 2 def increment(a): return a + 1 @compose(double_it, increment) def get_sum(*args): return sum(args) def add_attrs(**kwargs_): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): return func(*args, **kwargs) for key, value in kwargs_.items(): setattr(wrapper, key, value) return wrapper return decorator @add_attrs(test=True, ordered=True) def add(a, b): return a + b def main(): print(add(10, 5)) print(add.test) print(add.ordered) # print(get_sum(5)) # print(get_sum(20, 10)) # print(get_sum(5, 15, 25)) # print_args_kwargs([], [1], [1, 2], b=set(), w=set()) # print_args_kwargs(1, 2, 3, 4, b=300, w=40, t=50, a=100) # result = add_values(10, 20) # print(f"Результат: {result}, тип результата {type(result)}") # print(add(5, 4, 6, a=1, b=2)) # print(concatenate(a="Я", b="Выучу", c="Этот", d="Питон", e="!")) # print_args_kwargs(1, 2, 3, 4, b=300, w=40, t=50, a=100) ''' print(get_product(23, 5)) # Вычисляем в первый раз print(get_product(23, 5)) # Во второй раз срабатывает кеш time.sleep(5) print(get_product(23, 5)) # Кеш просрочился, поэтому вновь вычисляется значение ''' # original_func() # print(say_hello_to('Vasiliy', 'Ytkin')) if __name__ == '__main__': main()