python装饰器,细致讲解
1.储备知识
- 
*args,**kwargs
def index(x,y):
print(x,y)
def wrapper(*args,**kwargs):#接收参数
func(*args,**kwargs)#将参数打散 - 
名称空间与作用域:名称空间的“嵌套”是在函数定义阶段,即检测语法的时候确定的
 - 
函数对象:
- 
可以把函数当做参数传入
 - 
可以把函数当做返回值返回
 
 - 
 - 
def outter(func):
def wrapper():
pass
return wrapper - 
闭包函数
- 
函数B在函数A内部,并且函数B调用外层函数作用域的变量,那么函数B就是闭包函数
 - 
def funcA():
x=111
def funcB():
x
return funcB 
 - 
 - 
传递函数的方式
- 
通过参数的形式为函数传值
 - 
通过闭包的方式为函数传值
 
 - 
 
2.装饰器
- 
什么是装饰器
- 
定义一个函数,该函数在不修改原函数代码并且不改变调用方式的前提现,为被装饰的对象增加额外的功能
 
 - 
 - 
为何要用装饰器
- 
开放封闭原则
- 
开放:指的是对拓展功能是开放的
 - 
封闭:指的是对修改源代码是封闭的
 
 - 
 
 - 
 
3.得到装饰器思路
需求:在不修改index函数源代码以及调用方式的情况下为其添加统计时间的功能
def index(x,y):
    time.sleep(3)
    print('index %s %s'%(x,y))
index(111,222)
index(111,y=222)
index(x=111,y=222)
方案一:直接在index函数内加统计时间的代码
import time
def index(x,y):
    start = time.time()
    time.sleep(3)
    print('index %s %s'%(x,y))
    stop = time.time()
    print(stop-start)
    
index(111,333)
问题:没有修改代码的调用方式,但是修改了源代码,方案一失败
方案二:在函数调用的时候添加统计时间的代码
def index(x,y):
    time.sleep(3)
    print('index %s %s'%(x,y))
    
start = time.time()
index(111,222)
stop = time.time()
print(stop-start)
start = time.time()
index(333,444)
stop = time.time()
print(stop-start)
start = time.time()
index(555,666)
stop = time.time()
print(stop-start)
问题:没有修改index的源代码,也没有修改调用方式,并且加上了新功能,但是代码冗余。方案二失败
方案三:将方案二中冗余的代码部分写成函数
def index(x,y):
    time.sleep(3)
    print('index %s %s'%(x,y))
    
def swapper():      
    start = time.time()
    index(111,222)
    stop = time.time()
    print(stop-start)
    
 swapper()
问题:解决了代码冗余问题,但是函数的调用方式发生改变。方案三失败
方案三优化一:将index的参数写活
def index(x, y):
    time.sleep(3)
    print('index %s %s' % (x, y))
    
def swapper(*args,**kwargs):
    start = time.time()
    index(*args,**kwargs)
    stop = time.time()
    print(stop - start)
swapper(2222,54544)
方案三优化二:在优化一的基础上把被装饰的对象写活,原来只能装饰index
def index(x,y,z):
    time.sleep(3)
    print('index %s %s %s' %(x,y,z))
def home(name):
    time.sleep(2)
    print('welcome %s to home page' %name)
def outter(func):
    # func = index的内存地址
    def wrapper(*args,**kwargs):
        start=time.time()
        func(*args,**kwargs) # index的内存地址()
        stop=time.time()
        print(stop - start)
    return wrapper
index=outter(index) # index=wrapper的内存地址
home=outter(home) # home=wrapper的内存地址
方案三优化三:给wrapper添加返回值,达到以假乱真
def index(x,y,z):
    time.sleep(3)
    print('index %s %s %s' %(x,y,z))
def home(name):
    time.sleep(2)
    print('welcome %s to home page' %name)
def outter(func):
    def wrapper(*args,**kwargs):
        start=time.time()
        res=func(*args,**kwargs)
        stop=time.time()
        print(stop - start)
        return res
    return wrapper
# 偷梁换柱:home这个名字指向的wrapper函数的内存地址
# home=outter(home)
#
#
# res=home('egon') # res=wrapper('egon')
# print('返回值--》',res)
4.语法糖
import time
装饰器
def timmer(func):
    def wrapper(*args,**kwargs):
        start=time.time()
        res=func(*args,**kwargs)
        stop=time.time()
        print(stop - start)
        return res
    return wrapper
# 在被装饰对象正上方的单独一行写@装饰器名字
# @timmer # index=timmer(index)
def index(x,y,z):
    time.sleep(3)
    print('index %s %s %s' %(x,y,z))
# @timmer # home=timmer(ome)
def home(name):
    time.sleep(2)
    print('welcome %s to home page' %name)
index(x=1,y=2,z=3)
home('egon')
2.有参装饰器
1.知识储备
- 
由于语法糖@的限制,outter函数只能有一个参数,并且该参数只能接受被装饰对象的内存地址
 
def outter(func):
    # func =  被装饰函数的内存地址
    def wrapper(*args,**kwargs):
        res = func(*args,**kwargs)
        return res
    return wrapper
- 
index被装饰后(偷梁换柱之后)
- 
index的参数什么样子,wrapper的参数就应该什么样子
 - 
index的返回值什么样子,wrapper的返回值就应该什么样子
 - 
index的属性什么样子,wrapper的属性就应该什么样子==》from functools import wraps
 
 - 
 
2.有参装饰器
def auth(db_type):
    def deco(func):
        def wrapper(*args, **kwargs):
            name = input('your name>>>: ').strip()
            pwd = input('your password>>>: ').strip()
            if db_type == 'file':
                print('基于文件的验证')
                if name == 'egon' and pwd == '123':
                    res = func(*args, **kwargs)  # index(1,2)
                    return res
                else:
                    print('user or password error')
            elif db_type == 'mysql':
                print('基于mysql的验证')
            elif db_type == 'ldap':
                print('基于ldap的验证')
            else:
                print('不支持该db_type')
        return wrapper
    return deco
3.有参装饰器模板
def 有参装饰器(x,y,z):
    def outter(func):
        def wrapper(*args, **kwargs):
            res = func(*args, **kwargs)
            return res
        return wrapper
    return outter
                    
                
                
            
        
浙公网安备 33010602011771号