Записи по тегу “декоратор”.

Декораторы в Python

Декоратор в питоне это не одно и тоже что и декоратор в шаблонах проектирования как бы это показалось на первый взгляд. Декоратор в понимании шаблонов проектирования добавляет функциональность в runtime, а python декораторы делают это только во время определения функции. В этом и есть огромная разница между ними.
Далее под словом «декоратор» имеем ввиду python декоратор.
Декоратор определяется знаком @ и названием в начале функции. Пример (взят с вики):

  1. @viking_chorus
  2. def menu_item():
  3.     print "spam"

Данное определение эквивалентно

  1. def menu_item():
  2.     print "spam"
  3. menu_item = viking_chorus(menu_item)

Здравствуй аспектно ориентированное программирование. Теперь сам декоратор.

  1. def viking_chorus(myfunc):
  2.     def inner_func(*args, **kwargs):
  3.         for i in range(8):
  4.             myfunc(*args, **kwargs)
  5.     return inner_func

В итоге мы получим не что иное как вывод слова spam целых восемь раз. Декораторы как и любые функции могут принимать параметры.

Например

  1. def console(text_to_print):
  2.     def dec(func, *args, **kwargs):
  3.         print text_to_print
  4.         func(*args, **kwargs)
  5.     return dec
  6.  
  7. @console("ahtung")
  8. def index():
  9.     print "test"

Выведет сначала ahtung и только потом test.
Пример, если декорируемая функция получает дополнительные аргументы. Взят из пакета pybb, надеюсь автор не против =).

  1. def ajax(func):
  2.     def wrapper(request, *args, **kwargs):
  3.         if request.method == ‘POST’:
  4.             try:
  5.                 response = func(request, *args, **kwargs)
  6.             except Exception, ex:
  7.                 response = {‘error’: traceback.format_exc()}
  8.         else:
  9.             response = {‘error’: {‘type’: 403, ‘message’: ‘Accepts only POST request’}}
  10.         if isinstance(response, dict):
  11.             return JsonResponse(response)
  12.         else:
  13.             return response
  14.     return wrapper

И пример его использования

  1. @ajax
  2. def setstatus(request):
  3.     return {‘newstate’: ‘updated’, ‘date’: ‘2008-08-21}

Функция может быть задекорирована не только одним декоратором, их может быть несколько.

  1. @accepts(int,int)
  2. @returns(float)
  3. def bar(low,high):
  4.     pass

Или тоже самое в виде списка

  1. [@accepts(int,int), @returns(float)]
  2. def bar(low,high):
  3.     pass

Как оформлять дело каждого, но скорее более читабельным все таки является последовательное декорирование, то есть первый вариант.

Использовал материал и код из

Трека pybb:

http://pybb.org/browser/pybb/util.py

Вики:

http://en.wikipedia.org/wiki/Python_syntax_and_semantics#Decorators
http://ru.wikipedia.org/wiki/Python#.D0.94.D0.B5.D0.BA.D0.BE.D1.80.D0.B0.D1.82.D0.BE.D1.80.D1.8B

Офсайта:

http://www.python.org/dev/peps/pep-0318/