您的位置:首页 > 编程语言 > Python开发

python--装饰器

2012-09-11 11:47 549 查看
装饰器:对函数的包装

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: