本文假设读者已经知道如何编写基本的装饰器代码,否则请自行 google:“python 装饰器”and/or “python decorator”。
不带参数的装饰器
from functools import wraps
def object_does_not_exist(func):
@wraps(func)
def returned_wrapper(request, *args, **kwargs):
try:
return func(request, *args, **kwargs)
except ObjectDoesNotExist:
raise Http404()
return returned_wrapper
用法:
@object_does_not_exist
def detail(request):
pass
带参数的装饰器
-
第一种写法:
def object_does_not_exist(redirect=None): def decorator(func): @wraps(func) def returned_wrapper(request, *args, **kwargs): try: return func(request, *args, **kwargs) except ObjectDoesNotExist: if redirect: return HttpResponseRedirect(redirect) else: raise Http404() return returned_wrapper return decorator
用法:
@object_does_not_exist(redirect='/') def detail(request): pass # 记得加个闭合括号,否则会出现类似 takes exactly 1 argument (0 given) 的错误 @object_does_not_exist() def foo(request): pass
-
第二种写法:
def object_does_not_exist(func=None, redirect=None): def decorator(func): @wraps(func) def returned_wrapper(request, *args, **kwargs): try: return func(request, *args, **kwargs) except ObjectDoesNotExist: if redirect: return HttpResponseRedirect(redirect) else: raise Http404() return returned_wrapper if not func: def foo(func): return decorator(func) return foo else: return decorator(func)
用法:
@object_does_not_exist(redirect='/') def detail(request): pass @object_does_not_exist def foo(request): pass
第二种方法可以解决 got an unexpected keyword argument
错误。
参考
- Type and Flow: Python Decorator with Optional Keyword Arguments
- https://github.com/django/django/blob/master/django/contrib/auth/decorators.py
- https://github.com/django/django/blob/master/django/utils/http.py
- Signature Preserving Function Decorators | Numerical Recipes
- Python decorator notes - Helpful
Comments