在之前提到过,装饰器内部的函数已经取代了原有的函数(新的函数),那么这个函数会缺失很多属性
1 def is_admin(f): 2 def wrapper(*args, **kwargs): 3 if kwargs.get('usrename') != 'admin': 4 raise Exception("Now allow") 5 return f(*args, **kwargs) 6 return wrapper 7 8 def foobar(username="soneone"): 9 """ DOcarzy stuff """10 pass11 12 13 >>> foobar.func_doc14 ' DOcarzy stuff '15 >>> foobar.__name__16 'foobar'17 >>> @is_admin18 def foobar(username="someone"):19 """Do carzy stuff"""20 pass21 22 >>> foobar.__doc__23 >>> foobar.__name__24 'wrapper'25 >>>
我们可以使用functools来解决
1 import functools 2 def is_admin(f): 3 @functools.wraps(f) 4 def wrapper(*args, **kwargs): 5 if kwargs.get('usrename') != 'admin': 6 raise Exception("Now allow") 7 return f(*args, **kwargs) 8 return wrapper 9 10 def foobar(username="soneone"):11 """ DOcarzy stuff """12 pass13 14 15 >>> foobar.__name__16 'foobar'17 >>> foobar.__doc__18 ' DOcarzy stuff '19 >>>
在我们的例子当中,我们总是给装饰器函数传入了username关键字作为参数,我们来构建一个更好的方案
用inspect
1 import functools 2 import inspect 3 4 def is_admin(f): 5 @functools.wraps(f) 6 def wrapper(*args, **kwargs): 7 8 func_args = inspect.getcallargs(f,*args,**kwargs) 9 print func_args10 if func_args.get('username') != 'admin':11 raise Exception("Now allow")12 return f(*args, **kwargs)13 return wrapper14 15 @is_admin16 def foobar(username, type="chocolate"):17 """ DOcarzy stuff """18 pass19 20 >>> foobar(username='admin')21 { 'username': 'admin', 'type': 'chocolate'}22 >>>