美文网首页
7.装饰器讲解系列之原理用法(上)

7.装饰器讲解系列之原理用法(上)

作者: 软件开发技术修炼 | 来源:发表于2022-04-26 22:58 被阅读0次
    最全装饰器知识点

    1、什么是装饰器

    本质上增强函数或类的功能的一个函数;
    通俗来讲,装饰器可以让一个Python函数拥有原本没有的功能,可以通过装饰器,变的强大漂亮。
    【比如孙悟空,通过炼丹炉、龙宫、拜师而获得火眼金睛、金箍棒、七十二变,而变得很厉害;但它始终是猴子(函数本身)】

    装饰器的几点属性:
    实质:是一个函数
    参数:是你要装饰的函数名(并非函数调用)
    返回:是装饰完的函数名(并非函数调用)
    作用:为已经存在的对象添加额外的功能
    特点:不需要对对象做任何的代码上的变动

    python中装饰器是随着程序的加载运行而自动加载的,跟调不调用方法没有关系.所以只要是装饰器内部函数以外的部分都会自动加载执行,不用调用。

    2、为何引入装饰器

    实例一:

    一个简单的函数,增加其他属性,但不影响原代码

    #孙悟空吃桃子
    def sun():
        print('eat peach')
    sun()
    
    # 想增加一个sun可以有火眼金睛,不破坏原代码基础上
    def lian_dan(func):
        def change(*args,**kwargs):
            print("火眼金睛")
            return func(*args,**kwargs)
        return change
    
    @lian_dan   
    # 引用装饰器(把下面的孙放进炼丹炉里,并把新的复制给下方函数)
    def sun():
        print('eat peach')
    
    sun()
    #结果:
    火眼金睛
    eat peach
    
    -----------不使用装饰器----------
    def sun():
        print('eat peach')
    
    new_sun = lian_dan(sun())    #放入材料,原来孙悟空将方案给新的孙悟空
    sun()    #执行炼丹程序,新孙悟空出世
    
    实例二:

    不影响原代码基础上,增加权限

    
    def play():
        print('开始播放"孙悟空')
    
    play()
    
    userAge = 50
    def canYou(func):
        def decorator(*args,**kwargs):
            # 加权限认证  
            if userAge > 1 and userAge < 10:
                return func(*args,**kwargs)
            print('your age is not right')
        return decorator
    
    @canYou
    def play():
        print('开始播放"孙悟空')
    
    play()
    # 结果:
    your age is not right
    
    实例三:

    一次性在一个函数上用多个装饰器,代码执行顺序,从内到外

    def lian_dan(func):
        def change(*args,**kwargs):
            print('火眼金睛')
            return func(*args,**kwargs)
        return change
    
    def long(func):
        def hi(*args,**kwargs):
            print('金箍棒')
            return func(*args,**kwargs)
        return hi
    
    def baishi(func):
        def teach(*args,**kwargs):
            print("七十二变")
            return func(*args,**kwargs)
        return teach
    
    @baishi
    @long
    @lian_dan
    def sun():
        print('eat peach')
    
    sun()
    #结果:
    七十二变
    金箍棒
    火眼金睛
    eat peach
    # 代码执行顺序,从内到外
    

    3、装饰器可以解决哪些实际问题

    实际应用:用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。

    比如,需要计算两数相加的时间,两数相减的时间

    # 函数
    import time
    
    def add(a,b):
      start_time = time.time()
      res = a+b
      exec_time = time.time() - start_time
      return res
    
    使用装饰器

    装饰器函数的外部函数传入我要装饰的函数名字,返回经过装饰后函数的名字;内层函数(闭包)负责修饰被修饰函数

    import time
    # 定义装饰器
    def time_calc(func):
      def wrapper(*args, **kargs):
        # 可以自定义传入的参数
        print(func.__name__)
        start_time = time.time()
        f = func(*args, **kargs)
        exec_time = time.time() - start_time
        # 返回传入的方法名参数的调用
        return f
      # 返回内层函数的函数名
      return wrapper
    
    # 使用装饰器
    @time_calc
    def add(a,b):
      return a+b
    
    @time_calc
    def sub(a,b):
      return a-b
    
    add(1,3)
    sub(2,9)
    
    运行结果

    4、装饰器背后原理

    在上面代码中:
    1、func是我要装饰器的函数,我想用装饰器显示func函数运行的时间;
    2、@decorator这个语法相当于 执行 func = decorator(func),为func函数装饰并返回;
    3、装饰器函数 - decorator,该函数的传入参数是func (被装饰函数),返回参数是内层函数;
    4、这里的内层函数-wrapper,其实就相当于闭包函数,它起到装饰给定函数的作用,wrapper参数为args, kwargs。args表示的参数以列表的形式传入;kwargs表示的参数以字典的形式传入

    def wrapper(*args,**kwargs):
        print("args:", end= ' ')
        print(args)
        print("kwargs:", end=' ')
        print(kwargs)
    
    wrapper(["hi"],123,k = 110,p = 112)
    # 结果:
    args: (['hi'], 123)
    kwargs: {'k': 110, 'p': 112}
    

    5、@符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作
    如没有使用@time_calc时,调用时,需要加上
    tic = time_calc(sub)

    6、如果有其他的类似函数,可以继续调用装饰器来修饰函数,而不用重复修改函数或增加新的封装;
    归因于 python的函数可像普通对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可作为返回值,可被定义在另外一个函数内

    最后,想弄懂装饰器,可先点击学习下之前讲解的 4.闭包
    关于装饰器,还有两篇进行讲解,关注我,查看系列文章,完全搞定它!

    相关文章

      网友评论

          本文标题:7.装饰器讲解系列之原理用法(上)

          本文链接:https://www.haomeiwen.com/subject/sfrtsrtx.html