装饰器研究
装饰器种类
装饰器分为两类,一种是不需要参数的装饰器,另一种需要带参数。
下面展示一个不带参数的装饰器,实现简单的类似AOP功能,记录函数运行时间,或者记录日志等。
def running_time(func):
@functools.wraps(func) #备注
def wrapper(*args, **kw):
start_time = time.time()
ret = func(*args, **kw)
end_time = time.time()
print '[{0}()] done, run time : {1} sec'.format(func.__name__, end_time - start_time)
return ret
return wrapper
@running_time
def nothing():
for x in xrange(10):
print "Maybe YJ ,have a try"
对于带参数的装饰器,需要进行二级封装,在上面装饰器的基础上,在封装一层。示例代码如下:
def mydecorator(arg1, arg2):
def _mydecorator(function):
def __mydecorator(*args, **kw):
# 借助参数做些什么事情
res = function(*args, **kw)
return res
return __mydecorator()
return _mydecorator
注意functools.wraps()函数的作用:调用经过装饰的函数,相当于调用一个新函数,那查看函数参数,注释,甚至函数名的时候,就只能看到装饰器的相关信息,被包装函数的信息被丢掉了。而wraps则可以帮你转移这些信息。
f = running_time(nothing)
print f.__name_
输出结果会应为wraps包装而不同。
装饰器应用
除了前面介绍可以用于日志,运行时间等记录外。还有一些应用。
1 . 用来实现单例模式:
def singleton(cls, *args, **kw):
instances = {}
def _singleton():
if cls not in instances:
instances[cls] = cls(*args, **kw)
return instances[cls]
return _singleton
@singleton
class MyClass4(object):
a = 1
def __init__(self, x=0):
self.x = x
one = MyClass4()
two = MyClass4()
print id(one)
print id(two)
2 . 实现函数静态属性的注入
def static_var(**kwargs):
def decorate(func):
for varname, value in kwargs.iteritems():
setattr(func, varname, value)
return func
return decorate
@static_var(age=12)
def struggle2(number):
print number
print struggle2.age
struggle2.age += 1
struggle2(222)
这个静态属性,与全局变量不同,是函数专享的。
3 . 还有比如 参数检查,缓存, 代理,上下文提供者等应用。暂时没有使用经验。大概使用的情况都差不多。还是很实用的技术。