美文网首页
Python 闭包

Python 闭包

作者: eeert2 | 来源:发表于2020-05-03 22:57 被阅读0次

    在提到闭包之前,我们需要对函数做一些梳理:
    函数的局部参数是无法保存的,每次执行函数都是将参数初始化并执行

    闭包可以使函数拥有自己的环境上下文,在其中保存执行后的信息。使函数表现的像一个对象,丰富了函数的功能。

    0、引言


    我们现在要实现一个具有缓存功能的函数,"如果后续传入相同的参数,则不再计算,直接返回结果"

    如果是在对象中,这种缓存非常简单就能实现。但是在函数中则异常麻烦:

    • 1 幻想中的写法, [实际上并不能起到作用]
    import time
    
    
    def cache_sum(a, b):
        """这是一个具有缓存功能的求和函数"""
        cache = {}
    
        key = str(a) + str(b)
        if key in cache:            # 1. 具有缓存结果,则直接返回
            return cache.get(key)
        else:
                                    # 2. 计算
            time.sleep(1)
            ret = a + b
            cache[key] = ret        # 3. 将结果存储进缓存
    

    使用cache_sum

    if __name__ == '__main__':
        print(datetime.datetime.now())  # 2020-05-04 09:13:13.239913
        cache_sum(1, 5)
        print(datetime.datetime.now())  # 2020-05-04 09:13:14.242900
        cache_sum(1, 5)
        print(datetime.datetime.now())  # 2020-05-04 09:13:15.246474
    

    可以看出,在函数中cache = {}作为局部变量,每次都会被初始化,根本起不到作用 [ 两次执行都耗时一秒,说明缓存没有起作用]。

      1. 改进写法
    def cache_sum(a, b):
        """这是一个具有缓存功能的求和函数"""
    
        key = str(a) + str(b)
        if key in cache:  # 1. 这里的 cache 由使用者提供
            return cache.get(key)
        else:
            # 2. 计算
            time.sleep(1)
            ret = a + b
            cache[key] = ret  # 3. 将结果存储进缓存
    

    使用 cache_sum

    if __name__ == '__main__':
        cache = {}
    
        print(datetime.datetime.now())  # 2020-05-04 09:19:43.842472
        cache_sum(1, 5)
        print(datetime.datetime.now())  # 2020-05-04 09:19:44.846783
        cache_sum(1, 5)
        print(datetime.datetime.now())  # 2020-05-04 09:19:44.846864
    

    [ 第二次没有耗时,说明缓存起作用了]
    在这种写法中,我们执行cache_sum还需要提供 cache = {}这样一个变量,这样会引起很多问题:

    • 使用者会不会忘记提供 cache = {}?

    • 使用者会不会在外部修改 cache?
      这些都是无法预料的问题。显然不能作为这个问题的解决方式

      1. 使用闭包完成
    import time
    
    
    def as_cache_sum():
        """返回一个具有缓存功能的函数
    
        你应该这样使用它
    
        cache_sum = as_cache_sum()
        ret = cache_sum(1,4)
        print(ret)  # 5
        """
        cache = {}
    
        def cache_sum(a, b):
            key = str(a) + str(b)
            if key in cache:  # 1. 具有缓存结果,则直接返回
                return cache.get(key)
            else:
                # 2. 计算
                time.sleep(1)
                ret = a + b
                cache[key] = ret  # 3. 将结果存储进缓存
    
        return cache_sum
    

    第二种写法相比,这里提供变量cache是指外部函数中完成的,而使用者是接触不到这个变量的。

    细细的品,你是不是有点明白闭包的这个


    一、使用“闭包”

    “闭包”的本质是函数的嵌套定义,即在函数内部再定义函数。

    在下面这个函数中

     def make_averager():
            """返回一个计算平均值的函数"""
            series = []
    
            def averager(new_value):
                series.append(new_value)
    
                total = sum(series)
                return total / len(series)
    
            return averager
    

    调用 make_averager 时,返回一个 averager 函数对象。每次调用 averager 时,它会 把参数添加到系列值中,然后计算当前平均值。

    averager = make_averager()
    print(averager(10))  # 10
     
    print(averager(12))  # 11
    
    print(averager(14))  # 12
    
    

    在上述函数中make_averager并不包含真正的执行逻辑,它只做了两件事情

    • 为真正的执行函数提供环境上下文
    • 返回执行函数

    averager函数才是真正执行逻辑的地方,它使用了make_averager为它提供了series环境变量,averagerseries的修改会被保存起来(伴随着averager,直到其被销毁)

    相关文章

      网友评论

          本文标题:Python 闭包

          本文链接:https://www.haomeiwen.com/subject/nvpowhtx.html