python 装饰器和 functools 模块
2016-04-10 16:37
633 查看
python 装饰器和 functools 模块
在 python 语言里第一次看到装饰器不免让人想到设计模式中的装饰模式——动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
好吧,python 中的装饰器显然和装饰模式毫无关系。那 python 中的装饰器到底是什么呢?
简而言之,装饰器提供了一种方法,在函数和类定义语句的末尾插入自动运行代码。python 中有两种装饰器:函数装饰器和类装饰器。
从上面运行后结果看出,装饰器就是一个能够返回可调用对象(函数)的可调用对象(函数)。
可以看出第一次调用
第二次调用
再看看一个装饰器类来实现的:
functools 模块中有三个主要的函数 partial(), update_wrapper() 和 wraps(), 下面我们分别来看一下吧。
看源码时发现这个函数不是用 python 写的,而是用 C 写的,但是帮助文档中给出了用 python 实现的代码,如下:
OK,可能一下子没看明白,那么继续往下看,看一下是怎么用的。我们知道 python 中有个
看这个函数的源代码发现,它就是把被封装的函数的 module, name, doc 和 dict 复制到封装的函数中去,源码如下,很简单的几句:
具体如何用我们可以往下看一下。
wraps() 函数把用 partial() 把 update_wrapper() 给封装了一下。
好,接下来看一下是如何使用的,这才恍然大悟,一直在很多开源项目的代码中看到如下使用。
什么是装饰器?
在 python 语言里第一次看到装饰器不免让人想到设计模式中的装饰模式——动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。好吧,python 中的装饰器显然和装饰模式毫无关系。那 python 中的装饰器到底是什么呢?
简而言之,装饰器提供了一种方法,在函数和类定义语句的末尾插入自动运行代码。python 中有两种装饰器:函数装饰器和类装饰器。
函数装饰器
简单的装饰器例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | def decorator(F): # 装饰器函数定义 print "I'm decorator" return F @decorator def foo(): print 'Hello World!' # 上面等价于 foo = decorator(foo) foo() """ I'm decorator Hello World! """ decorator(foo)() # 所以这里的输出与 foo() 相同 """ I'm decorator Hello World! """ |
具有封闭作用域的装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 2021 | def decorator(func): # 装饰器函数 print 'in decorator' def wrapper(*args): print 'in decorator wrapper' wrapper._calls += 1 print "calls = %d" % (wrapper._calls) func(*args) wrapper._calls = 0 return wrapper @decorator def foo(x, y): print "x = %d, y = %d" % (x, y) foo(1, 2) # 第一次调用 """ in decorator in decorator wrapper calls = 1 x = 1, y = 2 """ foo(2, 3) # 第二次调用 """ in decorator wrapper calls = 2 x = 2, y = 3 """ |
foo(1, 2)时,相当于
1 2 | foo = decorator(foo) foo(1, 2) |
foo(2, 3)时 foo 已经为 decorator(foo) 的返回值了
再看看一个装饰器类来实现的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 2021 | class decorator: # 一个装饰器类 def __init__(self, func): print 'in decorator __init__' self.func = func self.calls = 0 def __call__(self, *args): print 'in decorator __call__' self.calls += 1 print "calls = %d" % (self.calls) self.func(*args) @decorator def foo(x, y): print "x = %d, y = %d" % (x, y) foo(1, 2) # 第一次调用 """ in decorator __init__ in decorator __call__ calls = 1 x = 1, y = 2 """ foo(2, 3) # 第二次调用 """ in decorator __call__ calls = 2 x = 2, y = 3 """ |
装饰器参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 2021 | def decorator_wrapper(a, b): print 'in decorator_wrapper' print "a = %d, b = %d" % (a, b) def decorator(func): print 'in decorator' def wrapper(*args): print 'in wrapper' func(*args) return wrapper return decorator @decorator_wrapper(1, 2) # 这里先回执行 decorator_wrapper(1, 2), 返回 decorator 相当于 @decorator def foo(word): print word foo('Hello World!') """ in decorator_wrapper a = 1, b = 2 in decorator in wrapper Hello World! """ |
functools 模块
functools 模块中有三个主要的函数 partial(), update_wrapper() 和 wraps(), 下面我们分别来看一下吧。
partial(func[,args][, *keywords])
看源码时发现这个函数不是用 python 写的,而是用 C 写的,但是帮助文档中给出了用 python 实现的代码,如下:1 23 | def partial(func, *args, **keywords): def newfunc(*fargs, **fkeywords): newkeywords = keywords.copy() newkeywords.update(fkeywords) return func(*(args + fargs), **newkeywords) newfunc.func = func newfunc.args = args newfunc.keywords = keywords return newfunc |
int([x[,base]])函数,作用是把字符串转换为一个普通的整型。如果要把所有输入的二进制数转为整型,那么就要这样写
int('11', base=2)。这样写起来貌似不太方便,那么我们就能用 partial 来实现值传递一个参数就能转换二进制数转为整型的方法。
1 23 | from functools import partial int2 = partial(int, base=2) print int2('11') # 3 print int2('101') # 5 |
update_wrapper(wrapper, wrapped[, assigned][, updated])
看这个函数的源代码发现,它就是把被封装的函数的 module, name, doc 和 dict 复制到封装的函数中去,源码如下,很简单的几句:1 23 | WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__') WRAPPER_UPDATES = ('__dict__',) def update_wrapper(wrapper, wrapped, assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES): for attr in assigned: setattr(wrapper, attr, getattr(wrapped, attr)) for attr in updated: getattr(wrapper, attr).update(getattr(wrapped, attr, {})) return wrapper |
wraps(wrapped[, assigned][, updated])
wraps() 函数把用 partial() 把 update_wrapper() 给封装了一下。1 23 | def wraps(wrapped, assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES): return partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 2021 | from functools import wraps def my_decorator(f): @wraps(f) def wrapper(*args, **kwds): print 'Calling decorated function' return f(*args, **kwds) return wrapper @my_decorator def example(): """这里是文档注释""" print 'Called example function' example() # 下面是输出 """ Calling decorated function Called example function """ print example.__name__ # 'example' print example.__doc__ # '这里是文档注释' |
相关文章推荐
- python对robotframework测试概要信息报告发送邮件的方法
- Python学习笔记第一天
- (python解析js)scrapy结合ghost抓取js生成的页面,以及js变量的解析
- 基于python和mysql的查询操作
- selenium+python send_keys() 上传文件
- python列出指定文件夹下所有给定后缀名的文件
- python:mysql查询
- python --yield
- 解析python中的类:
- 【python日常一】使用python抓取拉勾网职位信息并做简单统计分析
- python错误汇总3:安装MySQLdb时:EnvironmentError: mysql_config not found
- 一、Python 进阶 之 函数式编程
- caffe用python时可能需要的模块安装
- python中隐式的内存共享
- python中隐式的内存共享
- Python贴吧小爬虫
- Head First Python 学习札记 2016-04-09
- python练习_12
- odoo8新API multi 装饰类详解
- python:获取mysql版本