Декораторы в Python
Декоратор в питоне это не одно и тоже что и декоратор в шаблонах проектирования как бы это показалось на первый взгляд. Декоратор в понимании шаблонов проектирования добавляет функциональность в runtime, а python декораторы делают это только во время определения функции. В этом и есть огромная разница между ними.
Далее под словом «декоратор» имеем ввиду python декоратор.
Декоратор определяется знаком @ и названием в начале функции. Пример (взят с вики):
-
@viking_chorus
-
def menu_item():
-
print "spam"
Данное определение эквивалентно
-
def menu_item():
-
print "spam"
-
menu_item = viking_chorus(menu_item)
Здравствуй аспектно ориентированное программирование. Теперь сам декоратор.
-
def viking_chorus(myfunc):
-
def inner_func(*args, **kwargs):
-
for i in range(8):
-
myfunc(*args, **kwargs)
-
return inner_func
В итоге мы получим не что иное как вывод слова spam целых восемь раз. Декораторы как и любые функции могут принимать параметры.
Например
-
def console(text_to_print):
-
def dec(func, *args, **kwargs):
-
print text_to_print
-
func(*args, **kwargs)
-
return dec
-
-
@console("ahtung")
-
def index():
-
print "test"
Выведет сначала ahtung и только потом test.
Пример, если декорируемая функция получает дополнительные аргументы. Взят из пакета pybb, надеюсь автор не против =).
-
def ajax(func):
-
def wrapper(request, *args, **kwargs):
-
if request.method == ‘POST’:
-
try:
-
response = func(request, *args, **kwargs)
-
except Exception, ex:
-
response = {‘error’: traceback.format_exc()}
-
else:
-
response = {‘error’: {‘type’: 403, ‘message’: ‘Accepts only POST request’}}
-
if isinstance(response, dict):
-
return JsonResponse(response)
-
else:
-
return response
-
return wrapper
И пример его использования
-
@ajax
-
def setstatus(request):
-
return {‘newstate’: ‘updated’, ‘date’: ‘2008-08-21’}
Функция может быть задекорирована не только одним декоратором, их может быть несколько.
-
@accepts(int,int)
-
@returns(float)
-
def bar(low,high):
-
pass
Или тоже самое в виде списка
-
[@accepts(int,int), @returns(float)]
-
def bar(low,high):
-
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
Офсайта:
