python--装饰器
装饰器:对函数的包装
1--被装饰的函数不带参数
#"""无参数调用decorator声明时必须有一个参数,这个参数将接收要装饰的方法""" def deco(func):#deco对func进行包装 ... print 'start' ... func() ... print 'end' ... return func ... >>> @deco ... def my(): ... print 'is my' ... start is my end #注意:当使用上述方法定义一个decorator方法时,函数体内的额外操作只在被装饰的函数首次调用时执行, >>> my() is my #如果要保证额外操作在每次调用被装饰的函数时都执行,需要换成如下的写法: def deco(func): ... def wrapfunc(): ... print 'start' ... func() ... print 'end' ... return wrapfunc ... >>> @deco ... def myfunc(): ... print 'is myfunc' ... >>> myfunc() start is myfunc end
2--被装饰函数带参数
def deco(func): def newdeco(a, b):#被装饰函数的参数 print 'start' ret = func(a, b)#func被装饰函数 print 'end' return ret return newdeco >>> >>> @deco def myfunc(a, b): res = a + b print 'a + b = ',res >>> myfunc(10, 20) start a + b = 30 end
3--被装饰函数,所带参数不确定
def deco(func): def newdeco(*args, **kwargs): print 'start' print 'args = ',args print 'kwargs = ', kwargs res = func(*args, **kwargs) print 'end' return res return newdeco >>> @deco def myfunc(a, b):#被装饰函数有两个参数 res = a + b print "a + b = ", res >>> myfunc(1, 1) start args = (1, 1) kwargs = {} a + b = 2 end >>> @deco def myfunc(a, b, c ):#3个参数 res = a + b + c print "a + b +c = ", res >>> myfunc(1, 2, 3) start args = (1, 2, 3) kwargs = {} a + b +c = 6 end >>> @deco def myfunc(*args,**kwargs):#参数是列表与字典 sum = 0 i = 0 for eachnum in args: sum += eachnum print 'args[%d] = %d' %(i, eachnum) i += 1 print 'sum = ', sum for eachkey in kwargs.keys(): print '%s = %s' % (eachkey, kwargs[eachkey]) >>> myfunc(1, 2, 3,lady = 'gaga',shakira = 'isabel') start args = (1, 2, 3) kwargs = {'lady': 'gaga', 'shakira': 'isabel'} args[0] = 1 args[1] = 2 args[2] = 3 sum = 6 lady = gaga shakira = isabel end
4--装饰器带参数
这个装饰器参数是包在被装饰函数的外面的
def deco(args): def newdeco(func): def wrapfunc(): print 'in wrapfunc start,args =',args func() print 'end ****' return wrapfunc return newdeco >>> @deco("hello this is args of decorator") def myfunc():print 'is myfunc' >>> myfunc() in wrapfunc start,args = hello this is args of decorator is myfunc end ****
5--装饰器带参数(参数为类)
>>> class locker: def __init__(self): print 'locker.__init__()' @staticmethod#类的静态方法 def acquire(): print 'this is staticmethod method' @staticmethod def release(): print 'this is other staticmethod method' >>> def deco(cls): """ 装饰器的参数是个类,通过这个类,调用他的静态方法,装饰func()""" def newdeco(func): def wrapfunc(): print 'in wrapfunc' cls.acquire() try: return func() finally: cls.release() return wrapfunc return newdeco >>> @deco(locker) def myfunc():print 'is myfunc' >>> myfunc() in wrapfunc this is staticmethod method is myfunc this is other staticmethod method
6--用两个装饰器装饰函数
#!/usr/bin/env python # -*- coding: cp936 -*- """ This is decorator.py""" class Father: def __init__(self): print 'is Father.__init__()' @staticmethod def acquire(): print 'is Father.acquire()' @staticmethod def unlock(): print 'is Father.unlock()' class Sun(Father):#locker继承了myclass def __init__(self):#如果不重写__init__(),locker会自动调用父类的init()方法 print 'is Sun.__init__()' @staticmethod def acquire(): print 'is Sun.acquire()' @staticmethod def unlock(): print 'is Sun.unlock()' def deco(cls):#装饰函数的工具 def newdeco(func):#被装饰函数 def wrapfunc(*args, **kwargs):#被装饰函数的参数 print 'in wrapfunc start decorate' cls.acquire() try: return func(*args, **kwargs) finally: cls.unlock() return wrapfunc return newdeco class example:#不从任何父类继承 -- 经典类 @deco(Father)#选择mycalss当做装饰器函数 def myfunc1(self): print 'in example is myfunc1()' @deco(Father) @deco(Sun)#用了两个装饰器 def myfunc2(self, a, b): print 'in example is myfunc2()' res = a + b print 'a + b = ',res def main(): a = example() a.myfunc1()#myfunc1()输出被装饰的结果 print '*'*20 print a.myfunc1() print '*'*20 a.myfunc2(1, 2) if __name__ == '__main__': main() 运行脚本 python decorator.py 输出如下 in wrapfunc start decorate is Father.acquire() in example is myfunc1() is Father.unlock() ******************** in wrapfunc start decorate is Father.acquire() in example is myfunc1() is Father.unlock() None# 这个None -- print 会打印函数的返回值,函数没有返回值,所以打印None ******************** in wrapfunc start decorate#可以看出,装饰器的作用,先用调用Father装饰,所以Father这个装饰工具在最外层,里面的一层是Sun的装饰作用。离函数最近的装饰函数最先起作用,然后逐渐向外一层层的装饰 is Father.acquire() in wrapfunc start decorate is Sun.acquire() in example is myfunc2() a + b = 3 is Sun.unlock() is Father.unlock()
7--装饰的函数有返回值
参考:http://www.cnblogs.com/Jerry-Chou/archive/2012/05/23/2515004.html
def deco(func): def wrapfunc(): now = time() func() times = time() - now return times return wrapfunc @deco def my(): sum = 0 for i in range(100): sum +=i print 'sum = ',sum return sum >>> my() sum = 4950 0.016000032424926758 >>> print my() sum = 4950 0.0309998989105 >>> m = my() sum = 4950 >>> m 0.015999794006347656
my()这个函数,是有返回值的,返回sum,但是由于没有在装饰器中返回这个sum,所以运行my()这个被装饰的函数后,找不到他本身的返回值了
可以在wrapfunc()中返回这个sum
>>> def deco(func): def wrapfunc(): list = []#创建一个列表,存放多个返回值,或者返回一个字典,可以通过key来索引值,或者将返回值放在全局变量中 now = time() res = func() list.append(res) times = time() - now list.append(times) return list return wrapfunc >>> @deco def my(): sum = 0 for i in range(100): sum +=i print 'sum = ',sum return sum >>> my() sum = 4950 [4950, 0.04699993133544922]
8--example--利用装饰器计算函数调用时间
有3个数学函数,比较用单线程运行这3个函数,用多线程运行这3个函数所用时间
#!/usr/bin/env python # -*- coding: cp936 -*- """ This is mtfacfib.py""" from time import ctime, sleep, time import threading class MyThread (threading.Thread ):#线程类的子类 def __init__(self, func, args, name = ''): threading.Thread.__init__(self) self.name = name self.func = func self.args = args def getResult(self): return self.res def run(self): print 'starting', self.func.__name__, 'at:',\ ctime() #sleep(1) self.res = apply(self.func, self.args)#func函数运行的结果 print self.func.__name__, 'finished at:',ctime() """ This is the decorator""" def deco(func): def wrapfunc(): now = time() func() dict[func.__name__ + '_time'] = time() - now #return dict return wrapfunc def fib(x): sleep(0.005) if x < 2: return 1 return (fib(x - 2) + fib(x - 1)) def fac(x): sleep(0.1) if x < 2:return 1 return (x*fac(x-1)) def sum(x): sleep(0.1) if x < 2:return 1 return (x + sum(x-1)) """ data """ n = 12 dict = {} ssum = 0 funcs = [fib, fac, sum]#list nfuncs = range(len(funcs)) threads = [] @deco def calculate_single():#统计单线程时间 for i in nfuncs: print 'starting',funcs[i].__name__,'at:',\ ctime() res = funcs[i](n) print funcs[i].__name__, '=', res print funcs[i].__name__,'finished at:',\ ctime() #return res @deco def calculate_multiple():#统计多线程时间 for i in nfuncs: threads[i].start()#启动线程 sleep(1) for i in nfuncs: threads[i].join()#等待线程结束 print funcs[i].__name__, '=', threads[i].getResult() def main(): print '*** SINGLE THREAD***' calculate_single() print '\n*** MULTIPLE THREADS***' for i in nfuncs:#创建线程,建立时挂起 t = MyThread(funcs[i], (n,), funcs[i]) threads.append(t) calculate_multiple() print '*'*10, 'all done', '*'*10 for i in dict.keys(): print i,'=', dict[i] if dict['calculate_single_time'] > dict['calculate_multiple_time']: print 'single time > multiple time' else: print 'single time < multiple time' if __name__ == '__main__': main() 运行结果 python mtfacfib.py *** SINGLE THREAD*** starting fib at: Tue Sep 11 11:45:10 2012 fib = 233 fib finished at: Tue Sep 11 11:45:18 2012 starting fac at: Tue Sep 11 11:45:18 2012 fac = 479001600 fac finished at: Tue Sep 11 11:45:19 2012 starting sum at: Tue Sep 11 11:45:19 2012 sum = 78 sum finished at: Tue Sep 11 11:45:21 2012 *** MULTIPLE THREADS*** starting fib at: Tue Sep 11 11:45:21 2012 starting fac at: Tue Sep 11 11:45:22 2012 starting sum at: Tue Sep 11 11:45:23 2012 fac finished at: Tue Sep 11 11:45:23 2012 sum finished at: Tue Sep 11 11:45:24 2012 fib finished at: Tue Sep 11 11:45:28 2012 fib = 233 fac = 479001600 sum = 78 ********** all done ********** calculate_single_time = 10.0780000687 calculate_multiple_time = 7.31299996376 single time > multiple time