zoukankan      html  css  js  c++  java
  • 闭包与装饰器

    闭包和装饰器

    一、闭包

    二、装饰器

    回到顶部

    一、闭包

      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)
  • 相关阅读:
    FreeCommander 学习手册
    String详解, String和CharSequence区别, StringBuilder和StringBuffer的区别 (String系列之1)
    StringBuffer 详解 (String系列之3)
    StringBuilder 详解 (String系列之2)
    java io系列26之 RandomAccessFile
    java io系列25之 PrintWriter (字符打印输出流)
    java io系列24之 BufferedWriter(字符缓冲输出流)
    java io系列23之 BufferedReader(字符缓冲输入流)
    java io系列22之 FileReader和FileWriter
    java io系列21之 InputStreamReader和OutputStreamWriter
  • 原文地址:https://www.cnblogs.com/Mryang123/p/10055119.html
Copyright © 2011-2022 走看看