Python 装饰器 装饰器
04 July 2014
这是在Python学习小组上介绍的内容,现学现卖、多练习是好的学习方式。
第一步:最简单的函数,准备附加额外功能
'''
test1.py
最简单的函数,表示调用了两次
'''
def myfunc1():
print("myfunc() 1 called.")
myfunc1()
myfunc1()
结果
myfunc() 1 called.
myfunc() 1 called.
第二步:使用装饰函数在函数执行前和执行后分别附加额外功能
'''
test2.py
装饰函数的参数是被装饰的函数对象,返回原函数对象
装饰的实质语句: myfunc = deco(myfunc)
'''
def deco2(func):
print("before myfunc() 2 called.")
func()
print("after myfunc() 2 called.")
return func
def myfunc2():
print(" myfunc() 2 called.")
print
myfunc =deco2(myfunc2)
print
myfunc()
print
myfunc()
结果
before myfunc() 2 called.
myfunc() 2 called.
after myfunc() 2 called.
myfunc() 2 called.
myfunc() 2 called.
第三步:使用语法糖@来装饰函数
'''
test3.py
使用语法糖@来装饰函数,相当于“myfunc = deco(myfunc)”
但发现新函数只在第一次被调用,且原函数多调用了一次
'''
def deco3(func):
print("before myfunc() 3 called.")
func()
print("after myfunc() 3 called.")
return func
@deco3
def myfunc3():
print("myfunc() 3 called.")
myfunc3()
myfunc3()
结果
before myfunc() 3 called.
myfunc() 3 called.
after myfunc() 3 called.
myfunc() 3 called.
myfunc() 3 called.
第四步:使用内嵌包装函数来确保每次新函数都被调用
'''
test4.py
使用内嵌包装函数来确保每次新函数都被调用,
内嵌包装函数的形参和返回值与原函数相同,装饰函数返回内嵌包装函数对象
'''
def deco4(func):
def deco():
print("before myfunc() 4 called.")
func()
print(" after myfunc() 4 called.")
#不需要返回func,实际上应返回原函数的返回值
return deco
@deco4
def myfunc4():
print(" myfunc() 4 called.")
return 'ok'
myfunc4()
myfunc4()
结果
before myfunc4() called.
myfunc() 4 called.
after myfunc4() called.
before myfunc4() called.
myfunc() 4 called.
after myfunc4() called.
第五步:对带参数的函数进行装饰
'''
test5.py
对带参数的函数进行装饰,
内嵌包装函数的形参和返回值与原函数相同,装饰函数返回内嵌包装函数对象
'''
def deco5(func):
def deco(a, b):
print("before myfunc() called.")
ret =func(a, b)
print(" after myfunc() called. result: %s"%ret)
return ret
return deco
@deco5
def myfunc5(a, b):
print(" myfunc(%s,%s) called."%(a, b))
return a+b
ret1 = myfunc5(1, 2)
print ret1
ret2 = myfunc5(3, 4)
print ret2
结果
before myfunc() called.
myfunc(1,2) called.
after myfunc() called. result: 3
3
before myfunc() called.
myfunc(3,4) called.
after myfunc() called. result: 7
7
第六步:对参数数量不确定的函数进行装饰
'''
test6.py
对参数数量不确定的函数进行装饰,
参数用(*args, **kwargs),自动适应变参和命名参数
'''
def deco6(func):
def _deco(\*args, \*\*kwargs):
print("before %s called."%func.__name__)
ret =func(\*args, \*\*kwargs)
print(" after %s called. result: %s"%(func.__name__, ret))
return ret
return _deco
@deco6
def myfunc61(a, b):
print(" myfunc61(%s,%s) called."%(a, b))
return a+b
@deco6
def myfunc62(a, b, c):
print(" myfunc62(%s,%s,%s) called."%(a, b, c))
return a+b+c
myfunc61(1, 2)
print
myfunc61(3, 4)
print
myfunc62(1, 2, 3)
print
myfunc62(3, 4, 5)
结果
before myfunc61 called.
myfunc61(1,2) called.
after myfunc61 called. result: 3
before myfunc61 called.
myfunc61(3,4) called.
after myfunc61 called. result: 7
before myfunc62 called.
myfunc62(1,2,3) called.
after myfunc62 called. result: 6
before myfunc62 called.
myfunc62(3,4,5) called.
after myfunc62 called. result: 12
第七步:让装饰器带参数
'''
test7.py
在 test4\.py 的基础上,让装饰器带参数,
和上一示例相比在外层多了一层包装。
装饰函数名实际上应更有意义些
'''
def deco7(arg):
def _deco(func):
def __deco():
print("before %s called [%s]."%(func.__name__, arg))
func()
print(" after %s called [%s]."%(func.__name__, arg))
return __deco
return _deco
@deco7("module 1")
def myfunc71():
print(" myfunc71() called.")
@deco7("module 2")
def myfunc72():
print(" myfunc72() called.")
myfunc71()
print
myfunc72()
结果
before myfunc71 called [module 1].
myfunc71() called.
after myfunc71 called [module 1].
before myfunc72 called [module 2].
myfunc72() called.
after myfunc72 called [module 2].
第八步:让装饰器带类参数
'''
test8.py
装饰器带类参数
'''
class locker:
def __init__(self):
print("locker.__init__() should be not called.")
@staticmethod
def acquire():
print("locker.acquire() called.(这是静态方法)")
@staticmethod
def release():
print(" locker.release() called.(不需要对象实例)")
def deco8(cls):
'''cls 必须实现acquire 和 release 静态方法'''
def _deco(func):
def __deco():
print("before %s called [%s]."%(func.__name__, cls))
cls.acquire()
try:
return func()
finally:
cls.release()
return __deco
return _deco
@deco8(locker)
def myfunc8():
print(" myfunc() called.")
myfunc8()
myfunc8()