Kodomo

Пользователь

Декораторы

План рассказа

Полезные ссылки

Встроенные декораторы в питоне

staticmethod
про это расскажет Саша на следующем занятии
classmethod
про это расскажет Саша на следующем занятии
property
про это расскажет Саша на следующем занятии
contextlib.contextmanager
как просто делать свои обработчики входа и выхода для with
functools.wraps
вспомогательная обёртка для создания декораторов (копирует самодокументацию и пр.)

Идеи для декораторов

logging
записывать вызов и, например, аргументы функции в лог
profiling
записывать в лог длительность исполнения функции или суммарную длительность всех исполнений или суммарную длительность исполнений с одинаковыми аргументами
memoizing
запоминать результаты функции для заданного набора аргументов, чтобы не пересчитывать заново
once / lazyproperty
первый раз вызывать вычисление функции, последующие разы возвращать первый результат (фактически, синоним memoizing для функции без аргументов)
alias
создавать функцию сразу с несколькими именами
curry
создавать функцию, которая умеет выполнять операцию частичного вызова
typecheck
проверять типы аргументов функции (в момент вызова)
multimethod
выбирать, какое тело функции исполнять, в зависимости от типов аргументов
transaction
следить, чтобы все части действия либо выполнились вместе, либо из них не выполнилась ни одна; записывать информацию о совершённом действии так, чтобы его было легко отменить (это очень специфично в зависимости от конкретной области применения)
check_access
проверять права доступа перед исполнением функции

Генератор генераторов декораторов из (генераторов) итераторов

   1 import functools
   2 class Interface(object):
   3     def __init__(self, **kwargs):
   4         vars(self).update(kwargs)
   5 def gendecorator(geniterator):
   6     def make_decorator(*gen_args, **gen_kw):
   7         def decorator(fun):
   8             @functools.wraps(fun)
   9             def newfun(*args, **kw):
  10                 interface = Interface(args=args, kw_args=kw, fun=fun)
  11                 iterator = geniterator(interface, *gen_args, **gen_kw)
  12                 for _ in iterator:
  13                     assert not hasattr(interface, 'result'), (
  14                         "Generator '%s' must have exactly one yield" %
  15                         geniterator.__name__
  16                     )
  17                     interface.result = (
  18                         fun(*interface.args, **interface.kw_args)
  19                     )
  20                 return interface.result
  21             return newfun
  22         return decorator
  23     return make_decorator
  24 
  25 # Example use
  26 
  27 @gendecorator
  28 def returns(interface, type_):
  29     yield 
  30     assert type(interface.result) == type_
  31 
  32 @gendecorator
  33 def accepts(interface, *types, **kw_types):
  34     for arg, type_ in zip(interface.args, types):
  35         assert type(arg) == type_
  36     for name in kw_types:
  37         assert type(interface.kw_args[name]) == kw_types[name]
  38     yield
  39 
  40 import time
  41 @gendecorator
  42 def profiling(interface):
  43     begin = time.time()
  44     yield
  45     end = time.time()
  46     print "Time spent in %s: %0.5f" % (interface.fun.__name__, end - begin)
  47 
  48 @gendecorator
  49 def logging(interface):
  50     print "Entering %s" % interface.fun.__name__
  51     yield
  52     print "Leaving %s" % interface.fun.__name__
  53 
  54 @logging()
  55 @profiling()
  56 @accepts(int, int)
  57 @returns(int)
  58 def sum(a, b):
  59     return a + b

Контрольная работа