赞
踩
闭包(Closure)是函数式编程中的一个重要概念。在Python中,闭包可以简单理解为:一种特殊的函数。
在Python中,创建闭包非常简单。只需要定义一个外部函数,并在其中定义一个内部函数,内部函数引用外部函数的变量或参数,外部函数返回内部函数即可。
- # 定义一个名为 outer_function 的外部函数,它接受一个参数 x
- def outer_function(x):
-
- # 在外部函数内部定义一个局部变量 y,并赋值为 5
- y = 5
-
- # 在 outer_function 内部定义了一个嵌套函数 inner_function,它接受一个参数 z
- def inner_function(z):
-
- # 返回 x、y 和 z 三个变量的和
- # 注意:这里的 x 和 y 是来自外部函数 outer_function 的作用域(闭包)
- return x + y + z
-
- # outer_function 返回 inner_function 函数对象(而不是执行结果)
- # 当 outer_function 被调用时,它会创建一个新的 inner_function 实例,
- # 这个实例“记住”了当时 outer_function 作用域中的 x 和 y 的值
- return inner_function
-
- # 调用 outer_function 函数,传入参数 7,并将返回的 inner_function 赋值给 closure 变量
- # 此时,closure 变量实际上是一个函数对象,它“记住”了 x=7 和 y=5
- closure = outer_function(7)
-
- # 调用 closure 函数(即之前保存的 inner_function 实例),传入参数 9
- # 由于闭包的特性,尽管 outer_function 已经执行完毕,但 inner_function 仍然可以访问 x 和 y 的值
- result = closure(9)
-
- # 打印 result 的值,预期结果是 7(x的值)+ 5(y的值)+ 9(z的值)= 21
- print(result) # 输出:21
这段代码展示了闭包的一个基本应用。闭包是指一个能访问和操作其外部词法环境(lexical environment)的函数。
inner_function
是一个闭包,因为它访问了定义它的外部函数 outer_function
的作用域中的变量 x
和 y
。即使 outer_function
的执行已经结束,inner_function
仍然保持着对 x
和 y
的引用,并且可以在需要时被调用。outer_function(7)
被调用时,它创建了一个新的环境,其中 x
被赋值为 7,并且在这个环境中定义了 inner_function
。outer_function
返回了 inner_function
的一个实例(或者说是一个“绑定”了特定环境的函数对象)。这个返回的函数对象被赋值给了 closure
变量。closure(9)
时,实际上是调用了那个带有特定环境(x=7, y=5
)的 inner_function
实例。闭包的特性使得 inner_function
仍然能够访问到 x
和 y
的值,并将它们与传入的参数 z=9
相加,最终返回结果 21。闭包的主要作用有两个:
通过闭包,我们可以创建出具有“记忆”功能的函数,这些函数可以记住之前调用时的状态,从而实现一些特殊的功能,如计数器、缓存等。
在Python中,变量的查找遵循LEGB规则,即:Local -> Enclosing -> Global -> Built-in(由内向外查找)。当在函数内部访问一个变量时,Python会首先在当前函数的局部作用域中查找,如果找不到,则会在包含(enclosing)这个函数的作用域中查找,以此类推,直到找到为止。如果在所有作用域中都找不到,Python会抛出一个NameError
异常。
由于闭包可以记住并访问其所在的词法作用域,因此闭包中的内部函数在查找变量时,会先在其自身的局部作用域中查找,如果找不到,则会去其外部函数的词法作用域中查找。
闭包在Python中有许多应用场景,以下是一个具体的例子:
假设我们需要一个函数,每次调用它时都会记住之前的调用次数,并返回当前的调用次数。这种需求可以通过闭包来实现:
- def create_counter():
- count = 0 # 这是一个外部变量
-
- def counter():
- nonlocal count # 声明我们要引用的是外部变量
- count += 1 # 每次调用时,计数器加1
- return count # 返回当前的计数
-
- return counter # 返回内部函数,也就是闭包
-
- # 创建一个计数器
- my_counter = create_counter()
-
- # 调用计数器几次
- print(my_counter()) # 输出 1
- print(my_counter()) # 输出 2
- print(my_counter()) # 输出 3
在这个例子中,create_counter
函数返回了一个闭包counter
。这个闭包引用了外部变量count
,并且每次调用时都会使count
加1。由于闭包记住了其所在的词法作用域,即使create_counter
函数的执行上下文已经结束,counter
仍然可以访问和修改count
。
如果没有 nonlocal count 声明,Python会抛出 UnboundLocalErrorcounter
异常,这是因为Python在函数内部访问变量 count 时,会首先在当前函数的局部作用域中查找,而count += 1 会被Python 认为是一个新的局部变量,而不会去访问外部变量count = 0,因为 count
在 counter
函数内部从未被赋值过,所以会出现 UnboundLocalError
异常。
而 nonlocal
关键字的作用,就是告诉Python解释器 counter
函数内部的 count
变量是对外部作用域中的 count
变量的引用,而不是创建一个新的局部变量。
闭包和内嵌函数在编程中都是重要的概念,它们之间有一些相似之处,但也存在一些关键的区别。
nonlocal
)。而闭包则不同,即使其外部函数已经执行完毕,闭包仍然可以访问并操作其外部函数的变量,这是通过词法作用域实现的。综上所述,闭包和内嵌函数都允许内部函数访问外部函数的变量和参数,但闭包更加强调函数对外部环境的记忆能力,并且可以在外部函数外部被调用和使用。而内嵌函数则更侧重于在外部函数内部定义和使用。
虽然闭包非常强大和灵活,但在使用时也需要注意以下几点:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。