zoukankan      html  css  js  c++  java
  • Python之装饰器

    0.1高阶函数

    def sort(iterable,reverse=False,key=lambda x,y:x<y):
        lst = []
        for x in iterable:
            for k,v in enumerate(lst):
                if reverse:
                    flag=key(x,v)
                else:
                    flag= not key(x,v)
                if flag:
                    lst.insert(k,x)
                    break
            else:
                lst.append(x)
        return lst
    sort([2,5,6,1,4],reverse=True,key = lambda x,y:x>y)

    1.1currying
    指的是将原来接受两个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有第 二个参数为参数的函数

    def add(x,y):
    return x+y
    print(add(4,5)) 转换成
    def add(x): def _add(y): return x+y return _add print(add(5)(6))

    1.2装饰器的演变

    #业务功能分离,fn函数调用传参是个问题
    def add(x,y):
        return x+y
    def logger(fn):
        print('begin')
        x = fn(4,5)
        print('end')
        return x
    print(logger(add))

    解决了传参问题,进一步修改函数

    def add(x,y):
        return x+y
    def logger(fn,*args,**kwargs):
        print('begin')
        x = fn(*args,**kwargs)
        print('end')
        return x 
    print(logger(add,5,5))

    currying,改变函数调用的方式

    #currying
    def add(x,y):
        return x+y
    def logger(fn):
        def _logger(*args,**kwargs): #*args传参组成元祖,**kwargs传参组成字典
            print('begin')
            x = fn(*args,**kwargs) #*args,**kwargs是参数解构,此处fn调用了外层函数的参数fn是闭包 ;;add
            print('end')
            return x
        return _logger
    f = logger(add) #logger(add) 函数add已经传递进来给fn使用,左边重新赋值覆盖了add函数,引用计数后gc不垃圾回收
    print(f(5,6))
    f = logger(add)(5,6)  #currying的调用方式,;logger(add)外层函数return 内层函数wrapper
    print(f)
    add = logger(add)
    add(5,4)  #这个add调用的已经不是add函数了 而是增强版的add带装饰器的add
    logger(add)(4,5)  #等价于 add = logger(add)  -->add(4,5)

    装饰器语法糖

    def logger(fn):
        def wrapper(*args,**kwargs):
            x = fn (*args,**kwargs)
            return x 
        return wrapper
    @logger  #等价于 add = logger(add)
    def add(x,y):  #由于add = logger(add)-->这里的add已经不是函数定义了 而是logger返回的return wrapper
        return x+y  #return x+y 把返回值,传递给fn并且赋值给x,装饰器return x

    1.3装饰器的副作用,以及带参数的装饰器

    def copy_properties(src,dst):
        dst.__name__ = src.__name__
        dst.__doc__ = src.__doc__
    
    def logger(fn):
        def wrapper(*args,**kwargs):
            """I am wrapper"""
            x = fn(*args,**kwargs)
            return x
        copy_properties(fn,wrapper)
        return wrapper
    @logger
    def add(x,y):
        """This is function for add """
        return x+y
    print("name={},doc={}".format(add.__name__,add.__doc__))
    #备注参数wrapper.__name__=fn.__name__  ;fn的name属性是正常的 传递给wrapper的name属性
    更改后
    def copy_properties(src):
        def _copy_properties(dst):
            dst.__name__ = src.__name__
            dst.__doc__ = src.__doc__
            return dst
        return _copy_properties
    
    def logger(fn):
        @copy_properties(fn) #wrapper = copy_properties(fn)(wrapper)
        def wrapper(*args,**kwargs):
            """I am wrapper"""
            x = fn(*args,**kwargs)
            return x
        return wrapper
    @logger
    def add(x,y):
        """This is function for add """
        return x+y
    print("name={},doc={}".format(add.__name__,add.__doc__))

    带参数的装饰器

    #带参数的装饰器
    import datetime
    def logger(duration):
        def _logger(fn):
            def wrapper(*args,**kwargs):  #被装饰函数需要传递参数的时候,需要装饰器里面添加*args,*kwargs;没有warpper也是带参数的装饰器
                start = datetime.datetime.now()
                print('begin')
                x = fn(*args,**kwargs)
                end = datetime.datetime.now()
                print('too fast') if (end-start).total_seconds()<duration else print('too slow')    
                print('end')
                return x
            return wrapper
        return _logger
    @logger(5)
    def add(x,y):
        time.sleep(2)
        return x+y
    add(5,6)
    本文为原创文章,转载请标明出处
  • 相关阅读:
    思科 ASA 系列防火墙 官方文档下载指南
    Batch批量替换hosts
    OPCDA通信--工作在透明模式下的CISCO ASA 5506-X防火墙配置
    OPC DA通讯 KEP6.4 DCOM 配置脚本
    拖放获取文件信息的bat代码
    禁用UpdateOrchestrator重新启动任务
    SIAMATIC S7-1200 中通过 Modbus RTU 如何读取地址范围 9999 到 65535 的输入字
    提问的智慧 (提问前必读)
    [AHK]输入法状态提示,中文状态提示“中”,英文状态提示“EN”[转]
    Wincc V7.3SE安装截图
  • 原文地址:https://www.cnblogs.com/harden13/p/8874553.html
Copyright © 2011-2022 走看看