# -*- coding:utf-8 -*-
'''示例1: 最简单的函数,表示调用了两次'''
def myfunc():
print ("myfunc() called.")
myfunc()
myfunc()
E:\>py -3 a.py
myfunc() called.
myfunc() called.
第二步:使用装饰函数在函数执行前和执行后分别附加额外功能
'''示例2: 替换函数(装饰)装饰函数的参数是被装饰的函数对象,返回原函数对象
装饰的实质语句: myfunc = deco(myfunc)'''
defdeco(func):print ("before myfunc() called.")
func()print ("after myfunc() called.")returnfuncdefmyfunc():print ("myfunc() called.")
myfunc=deco(myfunc)
myfunc()
myfunc()
E:\>py -3 a.py
before myfunc() called.
myfunc() called.
after myfunc() called.
myfunc() called.
myfunc() called.
第三步:
'''示例3: 使用语法@来装饰函数,相当于“myfunc = deco(myfunc)”
但发现新函数只在第一次被调用,且原函数多调用了一次'''
defdeco(func):print ("before myfunc() called.")
func()print ("after myfunc() called.")returnfunc
@deco #等价于:deco(myfunc)defmyfunc():print ("myfunc() called.")
myfunc()
myfunc()
E:\>py -3 a.py
before myfunc() called.
myfunc() called.
after myfunc() called.
myfunc() called.
myfunc() called.
------->>>>>>
执行逻辑:
deco(myfunc)
print ("before myfunc() called.")
myfunc()
print (" after myfunc() called.")
print (" myfunc() called.")
print (" myfunc() called.")
第四步:使用内嵌包装函数来确保每次新函数都被调用
装饰器的规则:
规则1:
函数func上面定义了@xxxx,那么等价于 func = xxxx(func)
规则2:
装饰函数xxxx,必须返回一个闭包(一个内置函数+func)
'''示例4: 使用内嵌包装函数来确保每次新函数都被调用,
内嵌包装函数的形参和返回值与原函数相同,装饰函数返回内嵌包装
函数对象'''
defdeco(func):def_deco():print ("before myfunc() called.")
func()print ("after myfunc() called.")#不需要返回func,实际上应返回原函数的返回值
return_deco
@decodefmyfunc():print ("myfunc() called.")return 'ok'myfunc() #---->执行闭包函数_deco()
myfunc()#---->执行闭包函数_deco()
#myfunc=deco(myfunc)----->返回一个闭包:_deco的函数+myfunc
E:\>py -3 a.py
before myfunc() called.
myfunc() called.
after myfunc() called.
before myfunc() called.
myfunc() called.
after myfunc() called.
分析:
defdeco(func):def_deco():print ("before myfunc() called.")
func()print ("after myfunc() called.")#不需要返回func,实际上应返回原函数的返回值
return_deco
闭包:_deco+func
@decodefmyfunc():print ("myfunc() called.")return 'ok'myfunc=deco(myfunc)
myfunc是什么?是闭包:_deco+myfunc
myfunc()--->_deco()
myfunc()--->_deco()defouter(name):definner():print(name)returninner
闭包:inner+name
执行过程解释:
装饰函数deco
被装饰函数myfunc
@deco
def myfunc(): --->myfunc= deco(myfunc)
myfunc= deco(myfunc)干了什么呢?
1 调用了deco(myfunc)
2 返回闭包:_deco+外包变量myfunc
3 闭包赋值给了myfunc
4 提醒myfunc变为了闭包函数对象
myfunc()---》干了什么呢?
1 _deco()执行了
2 print ("before myfunc() called.")
3 myfunc()
4 print (" after myfunc() called.")
myfunc()---》干了什么呢?
1 _deco()执行了
2 print ("before myfunc() called.")
3 myfunc()
4 print (" after myfunc() called.")
第五步:对带参数的函数进行装饰
'''示例5: 对带参数的函数进行装饰,
内嵌包装函数的形参和返回值与原函数相同,装饰函数返回内嵌包装
函数对象'''
defdeco(func):def_deco(a, b):print ("before myfunc() called.")
ret=func(a, b)print ("after myfunc() called. result: %s" %ret)returnretreturn_deco
@decodefmyfunc(a, b):print ("myfunc(%s,%s) called." %(a, b))return a +b
myfunc(1, 2)
myfunc(3, 4)
E:\>py -3 a.py
before myfunc() called.
myfunc(1,2) called.
after myfunc() called. result: 3
before myfunc() called.
myfunc(3,4) called.
after myfunc() called. result: 7
第六步:对参数数量不确定的函数进行装饰
'''示例6: 对参数数量不确定的函数进行装饰,
参数用(*args, **kwargs),自动适应变参和命名参数'''
defdeco(func):def _deco(*args, **kwargs):print ("before %s called." % func.__name__)
ret= func(*args, **kwargs)print ("after %s called. result: %s" % (func.__name__, ret))returnretreturn_deco
@decodefmyfunc(a, b):print ("myfunc(%s,%s) called." %(a, b))return a+b
@decodefmyfunc2(a, b, c):print ("myfunc2(%s,%s,%s) called." %(a, b, c))return a+b+c
myfunc(1, 2)
myfunc(3, 4)
myfunc2(1, 2, 3)
myfunc2(3, 4, 5)
E:\>py -3 a.py
before myfunc called.
myfunc(1,2) called.
after myfunc called. result: 3
before myfunc called.
myfunc(3,4) called.
after myfunc called. result: 7
before myfunc2 called.
myfunc2(1,2,3) called.
after myfunc2 called. result: 6
before myfunc2 called.
myfunc2(3,4,5) called.
after myfunc2 called. result: 12
第七步:被装饰函数加参数:带参数的装饰器本质都是两层闭包
'''示例7: 在示例4的基础上,让装饰器带参数,
和上一示例相比在外层多了一层包装。
装饰函数名实际上应更有意义些'''
defdeco(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
@deco("mymodule")defmyfunc():print ("myfunc() called.")
@deco("module2")defmyfunc2():print ("myfunc2() called.")
myfunc()
myfunc2()
'''
1)多了一步:deco("hello") ---》返回了闭包:__deco+s
deco=闭包:__deco+s
2)@deco--->__deco(func)+s--->返回了一个闭包_deco+func+s
后面的过程跟上一步的过程一样。
'''
E:\>py -3 a.py
before myfunc called [mymodule].
myfunc() called.
after myfunc called [mymodule].
before myfunc2 called [module2].
myfunc2() called.
after myfunc2 called [module2].
第八步:让装饰器带 类 参数
'''示例8: 装饰器带类参数'''
classlocker:def __init__(self):print ("locker.__init__() should be notcalled.")
@staticmethoddefacquire():print ("locker.acquire() called.(这是静态方法)")
@staticmethoddefrelease():print ("locker.release() called.(不需要对象实例)")defdeco(cls):'''cls 必须实现acquire和release静态方法'''
def_deco(func):def __deco():print("before %s called [%s]." %(func.__name__, cls))
cls.acquire()try:returnfunc()finally:
cls.release()return __deco
return_deco
@deco(locker)defmyfunc():print ("myfunc() called.")
myfunc()
myfunc()
E:\>py -3 a.py
before myfunc called [].
locker.acquire() called.(这是静态方法)
myfunc() called.
locker.release() called.(不需要对象实例)
before myfunc called [].
locker.acquire() called.(这是静态方法)
myfunc() called.
locker.release() called.(不需要对象实例)
第九步:装饰器带类参数,并分拆公共类到其他py文件中,同时演示了对一个函数应用多个装饰器
'''mylocker.py: 公共类 for 示例9.py'''
classmylocker:def __init__(self):print("mylocker.__init__() called.")
@staticmethoddefacquire():print("mylocker.acquire() called.")
@staticmethoddefunlock():print("mylocker.unlock() called.")classlockerex(mylocker):
@staticmethoddefacquire():print("lockerex.acquire() called.")
@staticmethoddefunlock():print("lockerex.unlock() called.")deflockhelper(cls):'''cls 必须实现acquire和release静态方法'''
def_deco(func):def __deco(*args, **kwargs):print("before %s called." %func.__name__)
cls.acquire()try:return func(*args, **kwargs)finally:
cls.unlock()return __deco
return _deco
'''示例9: 装饰器带类参数,并分拆公共
类到其他py文件中
同时演示了对一个函数应用多个装饰
器'''
from mylocker import *
classexample:
@lockhelper(mylocker)defmyfunc(self):print ("myfunc() called.")
@lockhelper(mylocker)
@lockhelper(lockerex)defmyfunc2(self, a, b):print ("myfunc2() called.")return a +bif __name__=="__main__":
a=example()
a.myfunc()print(a.myfunc())print (a.myfunc2(1, 2))print (a.myfunc2(3, 4))