经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Python » 查看文章
闭包函数与装饰器
来源:cnblogs  作者:亚峰牛皮  时间:2019/11/13 8:58:39  对本文有异议

闭包函数与装饰器

一、什么是闭包函数

? 闭:封闭

? 包:包裹

? 闭包函数必须在函数内部定义

? 闭包函数可以引用外层函数的名字

? 闭包函数就是函数嵌套,函数对象,名称空间与作用域的结合体

二、闭包函数的传参

  • 直接传参

    def fun(x):
        print(x)
    
    func(1000)
  • 通过闭包函数传参

    def outer(num):
        def inner():
            print(num)
        return inner
    
    func = outer(100)#inner地址
    func()

三、装饰器及装饰器语法糖

  • 什么是装饰器

    装饰:装饰,修饰

    器:工具

  • 装饰器必须要遵循的‘开放封闭原则’

    开放:对函数功能的添加是开放的

    封闭:对函数功能的修改是封闭的

  • 装饰器的作用

    在不修改被装饰对象源代码与调用方式的前提下,添加新的功能

    被修饰对象:需要添加功能的函数

    装饰对象:添加功能函数

  • 应用

    统计时间

    登录认证

    可以解决冗余代码,提高代码可扩展性

  • 小实例结合time包

    import time
    # 被修饰函数
    def download_movie():#download_movie函数名
        print('开始下载电影')
        time.sleep(3)#模拟下载时间
        print('电影下载成功')
    
    start_time = time.time()
    download_movie()
    end_time = time.time()
    print(f'电影下载时间:{end_time - start_time}')
    >>>开始下载电影
    电影下载成功
    电影下载时间:3.0007519721984863
    
    #装饰器即装饰函数
    def time_record(func):#time_record装饰器的函数名,func形参,用来接收实参
        def inner():#内部函数名
            start_time = time.time()
            func()#执行接收到的函数
            end_time = time.time()
            print(f'电影下载时间:{end_time - start_time}')
        return inner#调用time_record这个函数返回inner的内存地址
    
    
    #print(time_record(download_movie))#time_record(download_movie)是一个内存地址
    download_movie = time_record(download_movie)
    download_movie()
    >>>开始下载电影
    电影下载成功
    电影下载时间:3.000049352645874
    开始下载电影
    电影下载成功
    电影下载时间:3.00085186958313
    
    #1、被修饰对象有返回值
    import time
    
    def download_movie():
        print('开始下载电影')
        time.sleep(3)#模拟下载时间
        print('电影下载成功')
    
        return '小泽.mp4'#调用函数返回'小泽.mp4'
    
    def time_record(func):#func<---download_movie
        def inner():
            start_time = time.time()
            res = func()#res = '小泽.mp4'
            # print(res)#res字符串
            end_time = time.time()
            print(f'电影下载时间:{end_time - start_time}')
            return res#调用函数inner返回res
        # print(inner())
        return inner#调用函数time_record返回inner,此时才是地址
    
    # print(time_record(download_movie))#inner地址
    download_movie = time_record(download_movie)
    download_movie()
    >>>开始下载电影
    电影下载成功
    电影下载时间:3.0000083446502686
    
    #2、被修饰对象有参数
    import time
    
    def download_movie(url):#url用来接收参数
        print('开始下载电影')
        time.sleep(3)#模拟下载时间
        print('电影下载成功')
        return '小泽.mp4'#返回'小泽.mp4'
    
    def time_record(func):#func用来接收被修饰函数func<---download_movie
        def inner(url):#url接收参数
            start_time = time.time()
            res = func(url)#func(url)<----download_movie(url)
            end_time = time.time()
            print(f'电影下载时间:{end_time - start_time}')
            return res#把res即(download_movie(url))---->inner
        return inner#(download_movie(url))---->time_record
    
    download_movie = time_record(download_movie)
    download_movie('https://www.jd.com/')
    >>>开始下载电影
    电影下载成功
    电影下载时间:3.0002450942993164
    
    #3、有多个参数
    import time
    
    def download_movie(*args, **kwargs):
        print('开始下载电影')
        time.sleep(3)#模拟下载时间
        print('电影下载成功')
        return '小泽.mp4'#把'小泽.mp4'
    
    def time_rcod(func):
        def inner(*args, **kwargs):
            start_time = time.time()
            res = func(*args, **kwargs)
            end_time = time.time()
            print(f'电影下载时间:{end_time - start_time}')
            return res
        return inner
    download_movie = time_rcod(download_movie)
    download_movie('https://www.baidu.com/')
    >>>开始下载电影
    电影下载成功
    电影下载时间:3.000089168548584
    
  • 装饰器模板

    def wrapper(func):
        def inner(*args,**kwargs):
            #添加功能
    
            res = func(*args,**kwargs)
    
            #添加功能
    
            return res
    
        return inner
    
    def func1():
        pass
    
    func1 = wrapper(func1)#func1被修饰函数,wrapper修饰函数
    func1()
  • 装饰器语法糖

    装饰器的语法糖是属于装饰器的

    @:装饰器的语法糖

    注意:在使用装饰器的语法糖时,装饰器必须定义在被装饰函数前

    # 统计函数执行时间装饰器
    def wrapper(func):  # 被装饰对象
        def inner(*args, **kwargs):  # 被装饰对象的参数
            # 调用前增加新功能
            start_time = time.time()
            # 调用被装饰对象,并接收返回值
            res = func(*args, **kwargs)
    
            # 调用后添加新功能
            end_time = time.time()
            print(end_time - start_time)
    
            return res
        return inner
    
    
    # func函数需要执行3秒
    
    # 无参装饰器
    # 使用装饰器
    @wrapper  # wrapper(func)  ---> func
    def func():
    
        time.sleep(3)
    

原文链接:http://www.cnblogs.com/yafeng666/p/11843169.html