python中的装饰器

一、什么是装饰器

装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。简单来讲,可以不严谨地把Python的装饰器看做一个包装函数的函数。

比如,有一个函数:

1 def func():
2     print 'func() run.'
3 
4 if '__main__' == __name__:
5     func()
6 运行后将输出:
7 func() run

 

现在需要在函数运行前后打印一条日志, 但是又不希望或者没有权限修改函数内部的结构, 就可以用到装饰器:

 1 def log(function):
 2     def wrapper(*args, **kwargs):
 3         print 'before function [%s()] run.' % function.__name__
 4         rst = function(*args, **kwargs)
 5         print 'after function [%s()] run.' % function.__name__
 6         return rst
 7     return wrapper 
 8 
 9 @log
10 def func():
11     print 'func() run.'
12 
13 if '__main__' == __name__:
14     func()

对于原来的函数"func()"并没有做修改,而是给其使用了装饰器log,运行后的输出为:

1 before function [func()] run.
2 func() run.
3 after function [func()] run.
4"@log"放到func()函数定义的地方,相当于执行了如下语句:
5 func = log(func)

因为log()返回了一个函数, 所以原本的func指向了log()返回的函数wrapper。wrapper的参数列表为(*args, **kwargs), 所以其可以接受所有的参数调用, 在wrapper中,先打印了一行

'before function [%s()] run.' % function.__name__,然后执行了原来的函数并记录了返回值,在输出

'after function [%s()] run.' % function.__name__ ,后返回了函数的执行结果。

以下为示例:

 1 def log(text=''):
 2     def decorator(function):
 3         @functools.wraps(function)
 4         def wrapper(*args, **kwargs):
 5             print 'before function [%s()] run, text: [%s].' % (function.__name__, text)
 6             rst = function(*args, **kwargs)
 7             print 'after function [%s()] run, text: [%s].' % (function.__name__, text)
 8             return rst 
 9         return wrapper
10     return decorator
11 
12 @log('log text')
13 def func():
14     print 'func() run.'
15 
16 if '__main__' == __name__:
17     func()
View Code

输出如下:

1 before function [func()] run, text: [log text].
2 func() run.
3 after function [func()] run, text: [log text].
多层装饰器
多重装饰器的应用:当要求每一个代码块需要两个或多个检查时,这样就需要两个或多个装饰器对此代码块进行监督。
下面给出一个使用装饰器同时对代码进行登录和权限的验证:
 1 USER_INFO={'is_login':True,'user_type':'2'}
 2 def check_login(func):
 3     def inner(*args,**kwargs):
 4         if USER_INFO.get('is_login',None):
 5             ret=func(*args,**kwargs)
 6             return ret
 7         else:
 8             print('没登录')
 9     return inner
10 def check_admin(func):
11     def inner(*args,**kwargs):
12         if USER_INFO.get('user_type',None)==2:
13             ret=func(*args,**kwargs)
14             return  ret
15         else:
16             print('权限不足')
17     return inner
18 
19 @check_login
20 @check_admin
21 def index():
22     print('管理员')
23 index()

 

posted @ 2016-06-04 11:15  百衲本  阅读(387)  评论(0编辑  收藏  举报
cnblogs_post_body { color: black; font: 0.875em/1.5em "微软雅黑" , "PTSans" , "Arial" ,sans-serif; font-size: 15px; } cnblogs_post_body h1 { text-align:center; background: #333366; border-radius: 6px 6px 6px 6px; box-shadow: 0 0 0 1px #5F5A4B, 1px 1px 6px 1px rgba(10, 10, 0, 0.5); color: #FFFFFF; font-family: "微软雅黑" , "宋体" , "黑体" ,Arial; font-size: 23px; font-weight: bold; height: 25px; line-height: 25px; margin: 18px 0 !important; padding: 8px 0 5px 5px; text-shadow: 2px 2px 3px #222222; } cnblogs_post_body h2 { text-align:center; background: #006699; border-radius: 6px 6px 6px 6px; box-shadow: 0 0 0 1px #5F5A4B, 1px 1px 6px 1px rgba(10, 10, 0, 0.5); color: #FFFFFF; font-family: "微软雅黑" , "宋体" , "黑体" ,Arial; font-size: 20px; font-weight: bold; height: 25px; line-height: 25px; margin: 18px 0 !important; padding: 8px 0 5px 5px; text-shadow: 2px 2px 3px #222222; } cnblogs_post_body h3 { background: #2B6695; border-radius: 6px 6px 6px 6px; box-shadow: 0 0 0 1px #5F5A4B, 1px 1px 6px 1px rgba(10, 10, 0, 0.5); color: #FFFFFF; font-family: "微软雅黑" , "宋体" , "黑体" ,Arial; font-size: 18px; font-weight: bold; height: 25px; line-height: 25px; margin: 18px 0 !important; padding: 8px 0 5px 5px; text-shadow: 2px 2px 3px #222222; } 回到顶部 博客侧边栏 回到顶部 页首代码 回到顶部 页脚代码