python学习笔记day12 装饰器进阶(二)

wraps

其实之前我们看到过,打印被修饰的函数名的时候发现已经不是自己了就是因为,@wrapper 其实就相当于func=wrapper(func) 在全局命名空间中,func已经不是原来定义的func函数了,而是装饰器函数内部的一个闭包函数inner 因为func是wrapper函数的返回值了,原来的func函数已经作为参数传递给wrapper函数的f参数了!

def wrapper(f):
    def inner(*args,**kwargs):
        ret=f(*args,**kwargs)
        return ret
    return inner
@wrapper
def func(a,b):
    print(a,b)
    return "哈哈哈"
print(func(1,2))
print(func.__name__)

运行结果:

其实我们可以借助functools中的wraps 是别人写好的装饰器函数,我们直接拿来用,效果就是可以使得加上装饰器扩充了功能的func函数变得看起来跟之前的调用一样啦:

from functools import wraps
def wrapper(f):
    @wraps(f)  #在装饰器函数内部的闭包函数上方加上@wraps(被装饰的函数名)
    def inner(*args,**kwargs):
        ret=f(*args,**kwargs)
        return ret
    return inner
@wrapper
def func(a,b):
    print(a,b)
    return "哈哈哈"

print(func(1,2))
print(func.__name__)

运行结果:

带有参数的装饰器(一个装饰器控制多个函数)

假设我们有一个场景:我们需要为写的众多函数加一个记录函数运行时间的功能,显然,我们可以使用装饰器来实现在不改变原函数功能的前提下,扩充该函数的功能,但是如果某一天,我们不需要记录这些函数的功能了,如果一个一个的删除@wrapper就真的太反人类了。在不需要大费周折的前提下,我们应该如何实现随时增加或者取消扩充函数的功能呢

Flag=1                       #是否需要使用装饰器给后续函数增加功能,只需要修改此参数
def wrapper_out(flag):       #在原来的基础上增加了一层函数,主要是通过参数flag来控制装饰器函数内部是否给被装饰的函数增加功能
    def wrapper(f):
        def inner(*args,**kwargs):
            if flag:
                print("在被装饰的函数之前执行")
                ret=f(*args,**kwargs)
                print("在被装饰的函数之后执行")
            else:
                ret=f(*args,**kwargs)
            return ret
        return inner
    return wrapper

@wrapper_out(Flag)
def func1(a,b):
    print(a,b)
    return "哈哈哈"
@wrapper_out(Flag)
def func2(a,b,c):
    print(a,b,c)
    return "嘻嘻嘻"

print(func1(1,2))
print(func2(2,3,4))

只需要在原来装饰器的基础上在外层扩充一层函数即可,通过传入参数flag来控制是否给原函数增加相应的功能,修改全局命名空间中全局变量Flag的值,Flag=1 行使装饰器函数的功能,Flag=0就是普通的为被装饰的函数执行;

多个装饰器函数装饰同一个函数

如果想给一个函数增加多个不同的功能,我们应该需要为一个函数写多个装饰器:

def wrapper1(f):
    def inner(*args,**kwargs):
        print("装饰器1在函数之前执行")
        ret=f(*args,**kwargs)
        print("装饰器1在函数之后执行")
        return ret
    return inner

def wrapper2(f):
    def inner(*args,**kwargs):
        print("装饰器2在函数之前执行")
        ret=f(*args,**kwargs)
        print("装饰器2在函数之后执行")
        return ret
    return inner

@wrapper1
@wrapper2
def func(a,b):            # 被装饰的函数
    print(a,b)
    return "哈哈哈哈"

#func=wrapper2(func)  #先看等号右侧,参数func就是全局空间中定义的函数func,传给了wrapper2函数的参数f=func,wrapper2返回的结果是inner 所以等号左边的func就是wrapper2中的inner函数名
#func=wrapper1(func)  #先看等号右侧,参数func其实就是上一行等式左边的func,也就是wrapper2函数返回的inner,这个inner作为wrapper1函数的参数f,等号左边的func就是wrapper1函数返回的inner
ret=func(1,2)         #先看等号右侧,这里的func其实就是上一步wrapper1函数返回的inner,,所以限制性wrapper1函数中的inner函数,
print(ret)            #最后返回的结果给了等号左侧的ret,最后打印

多个装饰器装饰同一个函数,其实应用场景就是比如一个装饰器记录函数运行时间,另一个装饰器记录函数调用~~~

最后代码的执行过程附图如下:

talk is cheap,show me the code
原文地址:https://www.cnblogs.com/xuanxuanlove/p/9571866.html