由浅入深分析python修饰器
2016-11-10 21:47
363 查看
单例模式的设计中有种方法,通过修饰器设计:
复习加深入思考单例模式的设计思路与原理
回到我们的问题,装饰器根本上也是一种方法,他形式上简单易用,可以反复应用在不同的函数上,比如:输出日志,打印调用时间。装饰器在一定程度上提取了复用的代码,增强原函数的功能。
分析完了为什么我们使用修饰器,我们现在从头开始分析修饰器是怎样形成的。
2,我们想添加一个功能,让他打印调用的时间,很简单,加入一行代码就够了(为了简单,本文省略import time语句)
3,我们的效果达到了,但是,如果有fun1,fun2,fun3也需要达到同样的效果,我们难道要每个函数都修改?这显然增加了毫无意义的劳动。我们何不专门定义一个函数,用来打印调用时间并执行函数
4,现在虽然目的达到了,但是如果在程序中显然更改了业务流程,本来调用hello函数,却变成了调用call_time函数(如果hello函数有参数,显然这种方法不可取)
5,我们可以定义一个函数,其功能为返回增强后的功能
6,如果我们的hello函数有一个参数,输入一个姓名,输出打招呼
这是我们修改一下代码,添加接收参数,一个简单的修饰器就形成了
结果为:
now time:1468135648943
hello
装饰器
函数
该函数完成等价于:
不难发现,函数f被with_logging取代了,当然它的
这个问题就比较严重的,好在我们有functools.wraps,wraps本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器函数中,这使得装饰器函数也有和原函数一样的元信息了。
内置
等效于
参考文章:https://www.zhihu.com/question/26930016/answer/99243411
def singleton(cls, *args, **kw): instances = {} def getinstance(): if cls not in instances: instances[cls] = cls(*args, **kw) return instances[cls] return getinstance @singleton class MyClass: ...
复习加深入思考单例模式的设计思路与原理
一、为什么要使用修饰器
先打一个比方,一个玻璃杯子,我们用来装水(功能),有一天,我们想装热水(增强后的功能),那我们需要在杯子外面套一个皮套(额外的功能),这时,皮套就起到了装饰器的功能,他提供了隔热的效果,使杯子有了装热水的功能。而且,这个皮套能够通用的套在不同的杯子上,达到同样的效果。回到我们的问题,装饰器根本上也是一种方法,他形式上简单易用,可以反复应用在不同的函数上,比如:输出日志,打印调用时间。装饰器在一定程度上提取了复用的代码,增强原函数的功能。
分析完了为什么我们使用修饰器,我们现在从头开始分析修饰器是怎样形成的。
二、由浅入深分析修饰器的形成
1,现在,我们有一个函数 hellodef hello(): print 'hello world'
2,我们想添加一个功能,让他打印调用的时间,很简单,加入一行代码就够了(为了简单,本文省略import time语句)
def hello(): print time.time() print 'hello world'
3,我们的效果达到了,但是,如果有fun1,fun2,fun3也需要达到同样的效果,我们难道要每个函数都修改?这显然增加了毫无意义的劳动。我们何不专门定义一个函数,用来打印调用时间并执行函数
def call_time(fun):
print time.time()
hello()
def hello(): print 'hello world'
call_time(hello)
4,现在虽然目的达到了,但是如果在程序中显然更改了业务流程,本来调用hello函数,却变成了调用call_time函数(如果hello函数有参数,显然这种方法不可取)
5,我们可以定义一个函数,其功能为返回增强后的功能
def call_time(fun):
def wrapper():
print time.time()
return hello() #这里添加return,如果hello有返回值则将其返回
return wrapper
def hello(): print 'hello world'
hello = call_time(hello)
hello()
python中定义了修饰器的语法规则,上述代码等同于:
def call_time(fun):
...
@call_time
def hello(): print 'hello world'
hello()
6,如果我们的hello函数有一个参数,输入一个姓名,输出打招呼
def hello(str): print 'hello %s'%str
这是我们修改一下代码,添加接收参数,一个简单的修饰器就形成了
简单的修饰器
def call_time(fun):
def wrapper(*args, **kw):
print time.time()
return hello(*args, **kw)
return wrapper
@call_time
def hello(str): print 'hello %s'%str
hello('TimorChow')
带参的修饰器
有时候我们需要给修饰器的功能传递一些参数,只要在现有的修饰器外加装一层接收参数的函数就好了def call_time_args(str): def call_time(fun): def wrapper(*args, **kw): print str,time.time() return hello(*args, **kw) return wrapper return call_time @call_time_args('now time') def hello(): print 'hello' hello()
结果为:
now time:1468135648943
hello
类装饰器
再来看看类装饰器,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器还可以依靠类内部的__call__方法,当使用 @ 形式将装饰器附加到函数上时,就会调用此方法。class Foo(object): def __init__(self, func): self._func = func def __call__(self): print ('class decorator runing') self._func() print ('class decorator ending') @Foo def bar(): print ('bar') bar()
functools.wraps
使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,比如函数的docstring、name、参数列表,先看例子:装饰器
def logged(func): def with_logging(*args, **kwargs): print func.__name__ + " was called" return func(*args, **kwargs) return with_logging
函数
@logged def f(x): """does some math""" return x + x * x
该函数完成等价于:
def f(x): """does some math""" return x + x * x f = logged(f)
不难发现,函数f被with_logging取代了,当然它的
docstring,__name__就是变成了with_logging函数的信息了。 print f.__name__ # prints 'with_logging' print f.__doc__ # prints None
这个问题就比较严重的,好在我们有functools.wraps,wraps本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器函数中,这使得装饰器函数也有和原函数一样的元信息了。
from functools import wraps
def logged(func):
@wraps(func)
def with_logging(*args, **kwargs):
print func.__name__ + " was called"
return func(*args, **kwargs)
return with_logging
@logged def f(x): """does some math""" return x + x * x
print f.__name__ # prints 'f'
print f.__doc__ # prints 'does some math'
内置
@staticmathod、@classmethod、@property的顺序
@a @b @c def f ():
等效于
f = a(b(c(f)))
参考文章:https://www.zhihu.com/question/26930016/answer/99243411
相关文章推荐
- 【Todo】Python面试题分析记录(修饰器等)
- Python源码分析3 – 词法分析器PyTokenizer
- python实现的AES双向对称加密解密与用法分析
- Python源码分析3 – 词法分析器PyTokenizer
- Python 文件操作技巧(File operation) 实例代码分析
- Python网络编程的一些代码片断与分析
- Linux后门系列--由浅入深sk13完全分析(缩水版)
- Python源码分析4 – Grammar文件和语法分析
- python下如何让web元素的生成更简单的分析
- Python 文件操作技巧(File operation) 实例代码分析
- Python使用Com组件及Access查询分析类实现
- 词频统计---python与C++的执行效率分析
- Linux后门系列--由浅入深sk13完全分析(缩水版)
- Python源码分析2 - 一个简单的Python程序的执行
- 模式分析和基于Python的DSLs的必要性
- Python使用Com组件及Access查询分析类实现
- Python源码分析1 - Building Python
- Python源码分析5 – 语法分析器PyParser
- Python源码分析5 – 语法分析器PyParser
- python与sqlite3分析