Python中的装饰器(语法糖)
装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志,性能测试,事务处理等。装饰器是为了解决这类问题的绝佳设计,抽离出大量函数中与函数本身无关的雷同代码并继续重用。装饰器的作用就是为了已经存在的对象添加额外的功能。装饰器是一个函数,用来包装函数的函数。第一步,一个简单的函数#!/usr/bin/pythondef myfunc():pr
装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志,性能测试,事务处理等。装饰器是为了解决这类问题的绝佳设计,抽离出大量函数中与函数本身无关的雷同代码并继续重用。装饰器的作用就是为了已经存在的对象添加额外的功能。
装饰器是一个函数,用来包装函数的函数。
第一步,一个简单的函数
#!/usr/bin/python
def myfunc():
print("myfunc() called")
myfunc()
执行结果:
myfunc() called
第二步,我想测试这个函数的时间性能。
#!/usr/bin/python
import time
def myfunc():
start = time.clock()
print("myfunc() called")
end = time.clock()
print ('time used is ',end-start)
myfunc()
执行结果:
myfunc() called
time used is 0.009169672696094571
可是,如果我还有一个函数叫myfunc2,我也想测试这个函数的时间开销。那么我是否需要复制一份代码呢,只是该一个函数名,这样太累赘了。
将测试时间开销的函数独立出来,这样就可以将业务和数据分离,代码可以很好的重用了。
第三步,分离业务逻辑和测试数据
#!/usr/bin/python
import time
def myfunc():
print("myfunc() called")
def timeit(func):
start = time.clock()
func()
end = time.clock()
print ('time used is ',end-start)
timeit(myfunc)
执行结果:
myfunc() called
time used is 0.01921845603380964
当我想在调用myfunc()的时候,就已经有测试时间性能的功能,而不需要额外的修改代码,即调用myfunc的效果相当于timeit(myfunc)
第四步,最少的改动
#!/usr/bin/python
import time
def myfunc():
print("myfunc() called")
def timeit(func):
def wrapper():
start = time.clock()
func()
end = time.clock()
print ('time used is ',end-start)
return wrapper
myfunc = timeit(myfunc)
myfunc()
执行结果为:
myfunc() called
time used is 0.0110723728723904
是否还能在简洁?可以的,使用语法糖@。
第五步,使用语法糖@降低字符输入量。
#!/usr/bin/python
import time
def timeit(func):
def wrapper():
start = time.clock()
func()
end = time.clock()
print ('time used is ',end-start)
return wrapper
@timeit
def myfunc():
print("myfunc() called")
myfunc()
执行结果为:
myfunc() called
time used is 0.013483512431895571
其作用和第四步的一样,只是用语法糖有一个限制,就是在装饰函数要在被装饰函数之前定义,不然就找不到装饰函数。如实例中所是,timeit函数要在myfunc函数之前定义。
第六步,对确定数量参数的函数进行装饰
#!/usr/bin/python
import time
def timeit(func):
def wrapper(a, b):
start = time.clock()
func(a, b)
end = time.clock()
print ('time used is ',end-start)
return wrapper
@timeit
def myfunc(a, b):
print("myfunc( %s, %s) called"%(a,b))
myfunc(1,2)
测试结果为:
myfunc( 1, 2) called
time used is 0.021083260107009123
第七步,对参数熟练不确定的函数进行装饰
#!/usr/bin/python
import time
def timeit(func):
def wrapper(*args, **kwargs):
start = time.clock()
func(*args, **kwargs)
end = time.clock()
print ('time used is ',end-start)
return wrapper
@timeit
def myfunc(a, b):
print("myfunc( %s, %s) called"%(a,b))
@timeit
def myfunc2(a, b, c):
print("myfunc2( %s, %s, %s) called"%(a,b,c))
myfunc(1,2)
myfunc2(1,2,3)
运行结果为:
myfunc( 1, 2) called
time used is 0.005005443617309361
myfunc2( 1, 2, 3) called
time used is 0.0040197501857303815
第七步,让装饰器带参数
#!/usr/bin/python
import time
def timeit(arg):
def _wrapper(func):
def wrapper(*args, **kwargs):
start = time.clock()
func(*args, **kwargs)
end = time.clock()
print ('time used is ',end-start, arg)
return wrapper
return _wrapper
@timeit("first time")
def myfunc(a, b):
print("myfunc( %s, %s) called"%(a,b))
@timeit("second time")
def myfunc2(a, b, c):
print("myfunc( %s, %s, %s) called"%(a,b,c))
myfunc(1,2)
myfunc2(1,2,3)
测试结果:
myfunc( 1, 2) called
time used is 0.01058011828321179 first time
myfunc( 1, 2, 3) called
time used is 0.005932319138874216 second time
第八步,python内置的装饰器,staticmethod、classmethod和property
functools模块提供了两个装饰器。这个模块是Python 2.5后新增的。
wraps(wrapped[, assigned][, updated]):
这是一个很有用的装饰器。函数是有几个特殊属性比如函数名,在被装饰后,上例中的函数名bar会变成包装函数的名字wrap,如果你希望使用反射,可能会导致意外的结果。这个装饰器可以解决这个问题,它能将装饰过的函数的特殊属性保留。
http://www.cnblogs.com/rollenholt/archive/2012/05/02/2479833.html
http://my.oschina.net/shniu/blog/215365?p=1
http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html
更多推荐
所有评论(0)