python的装饰器是一个非常有趣的特性。但是如果对decorator这一设计模式或者对Python语言不了解,初次看到这样的代码恐怕会觉得难以理解:
def baselog_decorator(func):
def log_wrapper(msg):
print('log: something happen.')
return func(msg)
return log_wrapper
下面结合例子说明一下Python中装饰器的用法。
比如我们现在有一个函数处理用户请求:
def request(msg):
print('request', msg)
在不改变现有函数功能前提下,我们希望能够在处理用户请求时打印日志信息(可以认为是为了调试用)。
定义一个装饰函数baselog_decorator,接受一个func作为入参。
其内部定义一个函数log _wrapper, 此函数打印日志,并调用func。
</pre><pre name="code" class="python">def baselog_decorator(func):
def log_wrapper(msg):
print('log: something happen.')
return func(msg)
return log_wrapper
有两点需要注意:
1)Python的函数内部可以定义函数;
2) Python的函数定义可以作为一个对象返回。
Python 的decorator的魔法尽在于此。
接下来,这样定义函数request:
@baselog_decorator
def request(msg):
print('request', msg)
这个写法其实等价于:
request = baselog_decorator(request)
相当于调用一个经过baselog_decorator 处理后的新的函数对象。
当你调用request, 比如 request('hahaha'),就会得到:
log: something happen.request hahaha
现在大家对装饰器应该有个基本的了解了。下面我们看一下更复杂一些的应用。
目前我们看过的装饰器还只是一个接受被装饰函数做为唯一入参的函数,我们希望装饰器可以接受参数,根据不同参数其行为也有变化。
比如我们的request响应用户请求,分为普通用户和VIP用户。我们的装饰器提供日志功能,但是对于不同用户的日志级别不同,普通用户输出到屏幕,VIP用户输出到服务器进行记录。那么如何接受定制参数(比如级别)呢?我们需要一些更加“邪恶”的魔法。
请大家看一下下面这个例子。normal_request和vip_request 是两种不同级别的用户的请求处理函数,我们需要为它们增加log信息,而对应log信息的实际处理应该有所不同。
def normal_request(msg):
print('normal_request', msg)
def vip_request(msg):
print('vip_request', msg)
我们期望的log输出的装饰器是这样,不但可以接受功能函数func,还可以指定级别:
def log_decorator(func, level):
def log_wrapper(msg):
if level is 'normal':
print('normal user action put to screen.')
else:
print('vip action put to server.')
return func(msg)
return log_wrapper
@log_decorator('normal') #使用时可以指定按'normal'级别装饰。
那么我们该怎么做呢?我们需要为装饰器再定义装饰器。
如下是我们新定义的装饰器。
def arg_decorator(decorator_func): #此装饰器接受功能装饰器(本例是提供log功能)
def arg_maker(*args, **kwargs): #此装饰器返回了一个新的函数arg_maker, 其接受定制参数
def arg_wrapper(func): #arg_maker本身又能返回一个真正包装的函数
return decorator_func(func, *args, **kwargs) #arg_maker 返回的包装函数内部,调用功能装饰器,并传入定制参数
return arg_wrapper
return arg_maker
#使用起来像这样:
@arg_decorator #用arg_decorator 装饰我们的功能装饰器,增加参数定制能力。
def log_decorator(func, level): #这个装饰器函数不但接受func,还带level参数,正是我们想要的。
def log_wrapper(msg):
if level is 'normal':
print('normal user action put to screen.')
else:
print('vip action put to server.')
return func(msg)
return log_wrapper #注意这里是最终的wrapper
#下面就是根据实际级别要求装饰函数了。
@log_decorator('normal')
def normal_request(msg):
print('normal_request', msg)
@log_decorator('vip')
def vip_request(msg):
print('vip_request', msg)
大家是不是有点晕呢,敲一下代码试一下吧。装饰器在Python中有广泛应用,比如@property和@staticmethod,应该要掌握这个知识。