def__call__(self, func): @wraps(func) defwrapper(*args, **kwargs): print('Before function %s call' % func.__name__) result = func(*args, **kwargs) print('After %s was called' % func.__name__) return wrapper
@MyDecorator3(5) defmy_func(): ...
Стосовно використання, то найчастіше декоратори на основі класів застосовують, коли необхідно зберігати деякий стан. Також, якщо логіка декоратора дещо складна і потрібно декілька додадкових методів (щоб все це знаходилося поруч). Для прикладу: декоратор, що рахує кількість викликів даної функції
def__call__(self, *args, **kwargs): self.times += 1 result = self.func(*args, **kwargs) print('Function %s has been called %d times' % (self.func.__name__, self.times)) return result
my_func() my_func()
Декоратор з опціональним параметром
Повернемося до декораторів на основі функцій і розглянемо таку ситуацію. Є декоратор, що приймає опціональний параметр
1 2 3 4
defdecorator1(argument=None): if argument isnotNone: print(argument) ...
Коли ми хочемо викликати його з параметром, ми пишемо
1 2 3
@decorator1(100) defmy_func(): ...
але коли опускаємо опціональний параметр
1 2 3
@decorator1() defmy_func(): ...
тобто, все одно доводиться писати дужки. Чи можна зробити так, щоб не потрібно було писати дужки, коли немає параметра. Звісно, відповідь позитивна, давай код
defdecorator(*args): func = None without_args = False if args: func, *decor_args = args ifcallable(func): without_args = True else: decor_args = args # Now you can use all arguments passed to decorator as decor_args defouter_wrapper(method): @wraps(method) defwrapper(*args, **kwargs): print('Before function %s call' % method.__name__) result = method(*args, **kwargs) print('After %s was called' % method.__name__) return result return wrapper if without_args: return outer_wrapper(func) return outer_wrapper
Просто додаємо ще одну перевірку, чи декоратор викликаний з аргументами, чи без і на основі цього передаємо потрібну обгортку. В результаті цей декоратор можна застосовувати будь-яким способом: @decorator, @decorator(), @decorator(1, 2, 3).
Отож, є мільярд варіантів як можна написати декоратор. Тут мав би бути ще якийсь логічний висновок стосовно вищесказаного, але не склалося.