python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python闭包与闭包陷阱

Python闭包与闭包陷阱举例详解

作者:专注算法的马里奥学长

闭包并不只是一个Python中的概念,在函数式编程语言中应用较为广泛,下面这篇文章主要给大家介绍了关于Python闭包与闭包陷阱的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下

1 什么是闭包

在 Python 中,闭包是一种特殊的函数,它能够记住它所在的环境(也称作上下文)。这意味着闭包能够访问定义它的作用域中的变量。闭包通常用于封装数据和提供对外部访问的接口。

在 Python 中使用闭包有以下几点好处:

2 闭包示例代码

代码示例如下:

def outer_func(x):
    def inner_func(y):
        return x + y
    return inner_func

closure = outer_func(10)
print(closure(5)) # 15

这是一个闭包的示例代码,其中outer_func是外部函数,它返回一个内部函数inner_func。内部函数使用了外部函数的变量x,并且在被调用时使用了参数y。因此,当我们调用outer_func(10)时,它返回了一个闭包(即inner_func),它记录了x=10的值。之后,我们可以调用这个闭包,并传入参数y来计算结果。

3 什么是闭包陷阱

Python中的闭包陷阱指的是在闭包中引用了变量时,如果该变量在闭包外部被修改,则闭包内部的值也会改变。这可能会导致程序的错误或意外行为。

4 闭包陷阱代码实例

请对比以下两组代码

4.1 第一组代码实例

def closure1():
    l = []
    for i in range(3):
        def inner(i_=i):
            return i_**2
        l.append(inner)
    return l


l1 = closure1()
print([i() for i in l1])

在执行代码时,首先i的在range(3)中获取的值为0,接下来执行l.append(inner)。这里inner并没有括号,所以inner本身不会被执行,而是在l中添加了一个inner函数对象。并且inner函数的形参i_默认值为0。

接下来,在for循环的作用下,l又被重复添加了两次inner对象,其中i_的默认值分别为1和2。

执行完closure1后,我们使用列表推到式去遍历l1

列表推导式中的i()使得inner对象被执行。因为i()中未传入任何参数,所以其中的i_使用了我们定义的默认参数:0,1,2。在执行完inner函数后,这些数字变成了0,1,4。因此最终的输出即为[0,1,4] 。

以上是一段正常的非闭包代码。

4.2 第二组代码实例

def closure2():
    l = []
    for i in range(3):
        def inner():
            return i**2
        l.append(inner)
    print(inner.__closure__)
    return l


l2 = closure2()
print([i() for i in l2])

这一组代码和上面一组代码没有很大的区别,唯一的差异是,这一组代码的inner并未传入形参i_。inner中的i直接取自外部。
因此,在执行closure2中的for循环时,l中依然会被传入3个inner函数对象,唯一的区别是传入的对象没有指定形参的默认值。
在执行[i() for i in l2]这个列表推到式时,inner函数并未找到对i的赋值,因此回到外部的closure2中去寻找,并找到了i的值为3。
因此,对于这段代码,每一个inner函数对象的输出都是4。

很明显这并不是我们想要的结果,这就是一个典型的闭包陷阱。

总结

到此这篇关于Python闭包与闭包陷阱举例的文章就介绍到这了,更多相关Python闭包与闭包陷阱内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文