• 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
  • 相关阅读:
    高性能NoSql数据库 SSDB
    Failed to connect socket to '/var/run/libvirt/libvirt-sock': No such file or directory
    Java基础-SSM之Spring的POJO(Plain Old Java Object)实现AOP
    Java基础-SSM之Spring的AOP编程
    Java基础-SSM之Spring快速入门篇
    Java基础-SSM之mybatis的统计函数和分页查询
    Java基础-SSM之mybatis一对一关联
    Java基础-SSM之mybatis多对多关联
    Java基础-SSM之mybatis的树形控件(自关联)
    Java基础-SSM之mybatis一对多和多对一关系映射
  • 原文地址:https://www.cnblogs.com/xuanxuanlove/p/9571866.html
Copyright © 2020-2023  润新知