写点什么

Python 进阶 (四) 浅谈 Python 闭包

  • 2022 年 10 月 08 日
    上海
  • 本文字数:900 字

    阅读完需:约 3 分钟

Python进阶(四)浅谈Python闭包

一、前言

在函数内部定义的函数和外部定义的函数是一样的,只是他们无法被外部访问:


def g():    print 'g()...'def f():    print 'f()...'    return g
复制代码


将 g 的定义移入函数 f 内部,防止其他代码调用 g:


def f():    print 'f()...'    def g():        print 'g()...'    return g
复制代码


但是,考察定义的 calc_sum 函数:


def calc_sum(lst):    def lazy_sum():        return sum(lst)    return lazy_sum
复制代码


注意: 发现没法把 lazy_sum 移到 calc_sum 的外部,因为它引用了 calc_sum 的参数 lst。


  • 像这种内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况,称为闭包Closure)。

二、闭包函数

闭包特点是返回的函数还引用了外层函数的局部变量,所以,要正确使用闭包,就要确保引用的局部变量在函数返回后不能变。举例如下:


# 希望一次返回3个函数,分别计算1x1,2x2,3x3:def count():    fs = [ ]    for i in range(1, 4):        def f():             return i*i        fs.append(f)    return fsf1, f2, f3 = count()
复制代码


你可能认为调用 f1(),f2()和 f3()结果应该是 1,4,9,但实际结果全部都是 9(请自己动手验证)。


原因就是当 count()函数返回了 3 个函数时,这 3 个函数所引用的变量 i 的值已经变成了 3。由于 f1、f2、f3 并没有被调用,所以,此时他们并未计算 i*i,当 f1 被调用时:


>>> f1()9     # 因为f1现在才计算i*i,但现在i的值已经变为3
复制代码


因此,返回函数不要引用任何循环变量,或者后续会发生变化的变量。


返回闭包不能引用循环变量,请改写 count()函数,让它正确返回能计算 1x1、2x2、3x3 的函数。


考察下面的函数 f:


def f(j):    def g():        return j*j    return g
复制代码


它可以正确地返回一个闭包 g,g 所引用的变量 j 不是循环变量,因此将正常执行。在 count 函数的循环内部,如果借助 f 函数,就可以避免引用循环变量 i。


参考代码:


def count():    fs = []    for i in range(1, 4):        def f(j):            def g():                return j*j            return g        r = f(i)        fs.append(r)    return fsf1, f2, f3 = count()print f1(), f2(), f3()
复制代码

三、程序实例


发布于: 刚刚阅读数: 3
用户头像

No Silver Bullet 2021.07.09 加入

岂曰无衣 与子同袍

评论

发布
暂无评论
Python进阶(四)浅谈Python闭包_Python_No Silver Bullet_InfoQ写作社区