久久不用,发现又忘了修饰器是怎么用的了。记在博客里会妥妥点。
一、 什么是修饰器:
1、以我的理解来说,修饰器就是为了给被修饰的函数进行预处理。什么是预处理呢?
比如说下面这个例子:
def myDeco(func):
print("Hello ,I'm Decorator!")
return func
@myDeco
def run():
print("func:run")
run()
def myDeco(func):
print("Hello ,I'm Decorator!")
return func
@myDeco
def run():
print("func:run")
run()
输出结果 :
ubuntu@yee:/tmp$ python test.py
Hello ,I'm Decorator!
func:run
ubuntu@yee:/tmp$ python test.py
Hello ,I'm Decorator!
func:run
可以看到,在执行run之前,先经过了myDeco来进行一些预处理。具体在现实中是如何运用的,下文再说。
处理参数
def myDeco(func):
print("Hello ,I'm Decorator!")
def _myDeco(*args,**kwargs): //被修饰的函数的参数
print("my name:%s",func.__name__)
ret = func(*args,**kwargs)
return ret
return _myDeco
@myDeco
def run(a,b):
print("func run start:")
print("---------------")
print("run(%s,%s)" % (a,b))
print("---------------")
print("func run end")
run(1,2)
def myDeco(func):
print("Hello ,I'm Decorator!")
def _myDeco(*args,**kwargs): //被修饰的函数的参数
print("my name:%s",func.__name__)
ret = func(*args,**kwargs)
return ret
return _myDeco
@myDeco
def run(a,b):
print("func run start:")
print("---------------")
print("run(%s,%s)" % (a,b))
print("---------------")
print("func run end")
run(1,2)
3、带参数的修饰器:
def myDeco(args):
print("Hello ,I'm Decorator!")
print("args:",args) //处理参数
def _myDeco(func)://处理函数
def __myDeco(*args,**kwargs): //处理函数的参数
print("my name:%s",func.__name__)
ret = func(*args,**kwargs)
return ret
return __myDeco
return _myDeco
@myDeco("my_name")
def run(a,b):
print("func run start:")
print("---------------")
print("run(%s,%s)" % (a,b))
print("---------------")
print("func run end")
run(1,2)
def myDeco(args):
print("Hello ,I'm Decorator!")
print("args:",args) //处理参数
def _myDeco(func)://处理函数
def __myDeco(*args,**kwargs): //处理函数的参数
print("my name:%s",func.__name__)
ret = func(*args,**kwargs)
return ret
return __myDeco
return _myDeco
@myDeco("my_name")
def run(a,b):
print("func run start:")
print("---------------")
print("run(%s,%s)" % (a,b))
print("---------------")
print("func run end")
run(1,2)
其它的还有“带类参数的修饰器”等一些高级特性,不过我没用过,就不记了。
二、具体应用 :
了解一些语法功能之后,总是需要知道它的应用场景吧,不然就没有用处了。
我以 tornado 这个web框架为例来说一下它的具体使用场景 。
先看代码就明白了:
class MessageNewHandler(BaseHandler,MessageMixin)://聊天室中的新消息处理,接收新消息
@tornado.web.authenticated //必须经过登录认证
def post(self):
user = self.get_current_user()
message = {
"id":str(uuid.uuid4()),
"current_user":user.id,
'up':0,
}
class MessageNewHandler(BaseHandler,MessageMixin)://聊天室中的新消息处理,接收新消息
@tornado.web.authenticated //必须经过登录认证
def post(self):
user = self.get_current_user()
message = {
"id":str(uuid.uuid4()),
"current_user":user.id,
'up':0,
}
上面的代码已经很明确了,在聊天室中的用户 post一条新消息之前,tornado会先检查用户是否已经登录认证了,只有经过认证的用户才可以post消息。
看看tornado.web.authenticated 是怎么实现的:
def authenticated(method):
"""Decorate methods with this to require that the user be logged in."""
@functools.wraps(method)
def wrapper(self, *args, **kwargs):
if not self.current_user:
if self.request.method in ("GET", "HEAD"):
url = self.get_login_url()
if "?" not in url:
if urlparse.urlsplit(url).scheme:
# if login url is absolute, make next absolute too
next_url = self.request.full_url()
else:
next_url = self.request.uri
url += "?" + urllib.urlencode(dict(next=next_url))
self.redirect(url)
return
raise HTTPError(403)
return method(self, *args, **kwargs)
return wrapper
def authenticated(method):
"""Decorate methods with this to require that the user be logged in."""
@functools.wraps(method)
def wrapper(self, *args, **kwargs):
if not self.current_user:
if self.request.method in ("GET", "HEAD"):
url = self.get_login_url()
if "?" not in url:
if urlparse.urlsplit(url).scheme:
# if login url is absolute, make next absolute too
next_url = self.request.full_url()
else:
next_url = self.request.uri
url += "?" + urllib.urlencode(dict(next=next_url))
self.redirect(url)
return
raise HTTPError(403)
return method(self, *args, **kwargs)
return wrapper
---------------------------------------------------------------
简单讲一下 functools.wraps 这个修饰器的作用:
update_wrapper,wraps ,而wraps 只是对 update_wrapper进行了封装一下而已。
在修饰器
def myDeco(func)
return func
def myDeco(func)
return func
这一句中,func 实际上已经丢掉了原func 的几个属性:__name__、__module__、__doc__和 __dict__,所以,返回后的函数你无法再使用 func.__doc__ 来获得注释内容 ,而如果改成这样:
def myDeco(func):
@functools.wraps(func)
def _myDeco(*args,**kwargs):
return func(*args,**kwargs)
return _myDeco
def myDeco(func):
@functools.wraps(func)
def _myDeco(*args,**kwargs):
return func(*args,**kwargs)
return _myDeco
则 functools.wraps 会帮你重新绑定在返回的新函数上。
---------------------------------------------------------------
说回到tornado 的例子,看它是怎么做认证 预处理的。
首先是:
if not self.current_user
if not self.current_user
判断是否当前用户(self.current_user是tornado的内置变量,保存当前登录的用户),如果不是,则抛出错误:
raise HTTPError(403)
raise HTTPError(403)
否则就返回 :
return method(self, *args, **kwargs)
return method(self, *args, **kwargs)
表示认证成功,开发者可以继续对认证成功的用户做应该做的动作。
这样子,python的修饰器如何应用 应该都明白 了。