• 闭包与装饰器


    闭包和装饰器

    一、闭包

    二、装饰器

    回到顶部

    一、闭包

      1.闭包的定义

        闭包是一种高阶函数, 函数名代表函数的引用, 函数名可以作为另一个函数的参数和返回值作用

      • 一个外部函数内定一个内函数
      • 内函数使用外函数的临时变量
      • 外函数返回内函数的引用

      2.闭包的作用

        隐藏功能的实现细节 

        闭包比类更加节省资源

        但是闭包不能完全代替类

      3.注意点

        当在内函数中使用外函数的局部变量时,可直接使用

        当在内函数中修改外函数的局部变量时,需要使用nonlocal声明

    二、装饰器

      1.装饰器概述

        功能:在已有函数基础上,在不改变函数代码及调用方式的基础前提下,为函数添加额外的功能

        语法:@xxxx

        装饰器原理:被装饰函数名指向了闭包中的内函数  # func = wrapper(func)

      2.装饰器的几种例子

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    # Author:Mr.yang
    """
        根据被装饰函数的定义形式不同(参数返回值)
        可以将装饰器定义成四种
        # 1. 无参 无返回值
        # 2. 有参 无返回值
        # 3. 无参 有返回值
        # 4. 有参 有返回值
    """
    # 1. 无参 无返回值
    def set_func1(func):
        def inner():
            print("调用前的装饰语句...")
            func()
            print("调用后的装饰语句...")
        return inner
    
    @set_func1
    def show1():
        print("show1...")
    
    # 2. 有参 无返回值
    def set_func2(func):
        def inner(string):
            print("调用前的装饰语句...")
            func(string)
            print("调用后的装饰语句...")
        return inner
    
    @set_func2
    def show2(string):
        print("show2...",  string)
    
    # 3. 无参 有返回值
    def set_func3(func):
        def inner():
            print("调用前的装饰语句...")
            res =  func()
            print("调用后的装饰语句...")
            return res
        return inner
    
    @set_func3
    def show3():
        return "show3..."
    
    # 4. 有参 有返回值
    def set_func4(func):
        def inner(string, n):
            print("调用前的装饰语句...")
            res =  func(string, n)
            print("调用后的装饰语句...")
            return res
        return inner
    
    @set_func4
    def show4(string, n):
        return "show4..." + string + str(n)
    
    if __name__ == '__main__':
        # show1()
        # show2('hello world')
        # print(show3())
        print(show4('哈哈', 666))
    闭包实现装饰器
    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    # Author:Mr.yang
    """
        根据被装饰函数的定义形式不同(参数返回值)
        可以将装饰器定义成四种
    """
    # def set_func(func):
    #     def inner(*args, **kwargs):
    #         print("装饰语句1...")
    #         res = func(*args, **kwargs)
    #         print("装饰语句2...")
    #         return res
    #     return inner
    
    # 使用通用装饰器实现计算时间的功能
    import time
    # 定义一个外函数,实现用作装饰器的闭包
    def set_func(func):
        def inner(*args, **kwargs):
            start = time.time()
            res = func(*args, **kwargs)
            end = time.time()
            print("公用 %.2f 秒" % (end - start))
            return res
        return inner
    
    @set_func
    def show1():
        print("show1...")
    
    @set_func
    def show2(string):
        print("show2...",  string)
    
    @set_func
    def show3():
        return "show3..."
    
    @set_func
    def show4(string, n):
        return "show4..." + string + str(n)
    
    @set_func
    def show5(n1, n2, n3):
        return n1 + n2 + n3
    
    if __name__ == '__main__':
        show1()
        show2('hello world')
        print(show3())
        print(show4('哈哈', 666))
        print(show5(1,2,3))
    通用闭包实现装饰器
    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    # Author:Mr.yang
    """
        使用类来实现来实现装饰器
    """
    # 实现装饰器类
    # 实现两个方法
    # init方法,用来接收被装饰函数的引用
    # call方法, 用让被装饰函数名调用时, 可以执行, 因为使用类装饰器后
    # 被装饰函数就不在指向原函数对象, 而是指向类的实例对象
    import time
    class CountTime(object):
        def __init__(self, func):
            self.__func = func
    
        # 这个方法才可以被装饰函数执行时, 真正执行的方法, 也就是闭包的内函数
        def __call__(self, *args, **kwargs):
            start = time.time()
            res = self.__func(*args, **kwargs)
            end = time.time()
            print("公用了 %s 秒" % ( end - start))
            return res
    
    
    @CountTime      # show1 = CountTime(show1)
    def show1():
        print("show1...")
    
    @CountTime
    def show2(string):
        print("show2...",  string)
    
    @CountTime
    def show3():
        return "show3..."
    
    @CountTime
    def show4(string, n):
        return "show4..." + string + str(n)
    
    @CountTime
    def show5(n1, n2, n3):
        return n1 + n2 + n3
    
    if __name__ == '__main__':
        show1()
        show2('hello world')
        print(show3())
        print(show4('哈哈', 666))
        print(show5(1,2,3))
    实现类装饰器

      3.装饰器传参

        概念:在使用过程中,除被装饰器函数外,还需要额外传入数据时,需要进行装饰器传参

        过程步骤:

    1. 先执行 set_args('参数') 得到 set_args 函数中的返回值,也就是 set_fun 函数的引用
    2. 然后返回的引用和 @ 进行组合,变成装饰器形式 @set_fun , 但是这时 set_fun 函数因为是返回的闭包引用,所以保留了args的参数值
    3. 再调用 show 的时候, show 还是指向的 wrapper 函数,但是在这个函数中,可以使用外面两层函数的变量或参数
    4. 无论在何时,闭包有几层,最终被装饰的函数永远指向 wrapper 函数

        代码示例:

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    # Author:Mr.yang
    
    """
    
    """
    # 路由表
    router_table = {}
    
    # 装饰器
    def router(url):
        def set_func(func):
            def inner(*args, **kwargs):
                return func(*args, **kwargs)
    
            # 实现将 url 作为key, 然后将 被装饰的函数作为值, 保存在路由表
            router_table[url] = inner
            return inner
        return set_func
    
    # 定义页面功能函数
    @router('index.html')
    def index():
        print('Index...')
    
    @router('center.html')
    def center():
        print('Center...')
    
    @router('new.html')
    def news():
        print('New...')
    
    def other():
        print("404...")
    
    # 模拟请求的方法
    def request_url(url):
        # 根据传入的请求地址, 来找到对应的页面
        print("请求的地址是 %s" % url)
        print("页面的内容是:")
    
        # 判断地址是否是某一个
        # if url == 'index.html':
        #     index()
        # elif url == 'center.html':
        #     center()
        # elif url == 'news':
        #     news()
        # else:
        #     other()
    
        if url in router_table:
            func = router_table[url]
        else:
            func = other
        func()
    
    if __name__ == '__main__':
        request_url('index.html')
        request_url('center.html')
        request_url('new.html')
        request_url('aaa.html')
        print(router_table)
  • 相关阅读:
    Ant Design Pro:Layout 组件——嵌套布局
    React实战之将数据库返回的时间转换为几分钟前、几小时前、几天前的形式。
    React实战之Ant Design—Upload上传_附件上传
    React实战之60s倒计时按钮(发送短信验证按钮)
    map方法到底会不会改变原始数组?
    【React】react开发vscode插件推荐
    【React】React 工程的 VS Code 插件及配置
    【React】react新特性实例详解(memo、lazy、suspense、hooks)
    数组常用slice和splice的区别
    【React】react-beautiful-dnd 实现组件拖拽
  • 原文地址:https://www.cnblogs.com/Mryang123/p/10055119.html
Copyright © 2020-2023  润新知