zoukankan      html  css  js  c++  java
  • python 装饰器

    需求:

    一个加法函数,想增强它的功能,能够输出加法函数的日志信息

    def add(x, y):
        return x + y

    增加信息输出功能:

    def add(x, y):
        print("call add,x + y") #日志输出到控制台
        return x + y

    上面的加法函数是完成了需求,但是有以下的缺点:

      打印日志信息是一个功能,这条语句和 add 函数耦合太高;

      加法函数属于业务功能,而输出日志信息的功能,属于非业务功能代码,不该放在业务函数 add 中;

    下面代码做到了业务功能分离,但是 fn 函数调用传参是个问题:

    def add(x, y):
        return x + y
    
    def logger(fn):
        print('before')
        print('add function:{} {}'.format(4, 5))
        ret = fn(4, 5)
        print('after')
        return ret
    
    print(logger(add))

    解决了传参的问题,进一步改变:

    def add(x, y):
        return x + y
    
    def logger(fn, *args, **kwargs):
        print('before')
        print('add function:{} | {}'.format(args, kwargs))
        ret = fn(*args, **kwargs)    # 参数解构
        print('after')
        return ret
    
    print(logger(add, 4, 5))
    print(logger(add, x=4, y=6))
    print(logger(add, 4, y=15))

    柯里化:

    def add(x, y):
        return x + y
    
    def logger(fn):
        def wrapper(*args, **kwargs):
            print('before')
            print('add function:{} | {}'.format(args, kwargs))
            ret = fn(*args, **kwargs)    # 参数解构
            print('after')
            return ret
        return wrapper
    
    print(logger(add)(4, 5))
    # 换一种写法:
    '''
    add = logger(add)
    print(add(x=5, y=10))
    '''
    # 1.先算等式右边,logger(add)
    # 2.add函数对象被fn记住
    # 3.logger函数返回 wrapper,即add = wrapper
    # 4.调用add(4, 5)即wrapper(4, 5)
    # 5.ret = fn(*args, **kwargs),此处的fn记住的是最原始的add函数对象

    装饰器语法糖:

    def logger(fn):
        def wrapper(*args, **kwargs):
            print('before')
            print('add function:{} | {}'.format(args, kwargs))
            ret = fn(*args, **kwargs)    # 参数解构
            print('after')
            return ret
        return wrapper
    
    @logger    # 等价于add = logger(add)
    def add(x, y):
        return x + y
    
    print(add(20, 30))
    '''
    可以采用逆推思维:
    1.add(20, 30)
    2.包装add(20, 30)为:wrapper(20, 30)
    3.实现日志增强功能:logger(add)(20, 30)
    即:add(20, 30) => wrapper(20, 30) => logger(add)(20, 30)
    
    def logger(fn):
        def wrapper(*args, **kwargs):
            val = fn(*args, **kwargs)
            return val
        return wrapper
    @logger
    def add(x, y):
        return x + y
    '''

    @logger是什么?这就是装饰器语法

    装饰器(无参)

      它是一个函数

      函数作为它的形参,无参装饰器实际上就是一个单形参函数

      返回值也是一个函数 可以使用 @functionname 方式,简化调用

      注:此处装饰器的定义只是就目前所学的总结,并不准确,只是方便理解

    装饰器和高阶函数

      装饰器可以是高阶函数,但装饰器是对传入函数的功能的装饰(功能增强)

  • 相关阅读:
    Java 第十一届 蓝桥杯 省模拟赛 梅花桩
    Java 第十一届 蓝桥杯 省模拟赛 梅花桩
    Java 第十一届 蓝桥杯 省模拟赛 梅花桩
    Java 第十一届 蓝桥杯 省模拟赛 元音字母辅音字母的数量
    Java 第十一届 蓝桥杯 省模拟赛 元音字母辅音字母的数量
    Java 第十一届 蓝桥杯 省模拟赛 元音字母辅音字母的数量
    Java 第十一届 蓝桥杯 省模拟赛 最大的元素距离
    Java 第十一届 蓝桥杯 省模拟赛 递增序列
    Java 第十一届 蓝桥杯 省模拟赛 递增序列
    Java 第十一届 蓝桥杯 省模拟赛 最大的元素距离
  • 原文地址:https://www.cnblogs.com/zyybky/p/12918913.html
Copyright © 2011-2022 走看看