Python 中的嵌套函数如何工作?

2025 年 1 月 4 日 | 阅读 8 分钟

在 Python 中,函数被视为一等公民。在一种语言中,一等公民的待遇始终如一。数据结构、控制结构和参数传递是它们的一些可能用途。如果一种编程语言将函数视为一等公民,那么它就被称为支持一等函数。Python 支持一等函数的概念。

一等函数的特点包括:

  • 对象类型的一个实例就是函数。
  • 函数可以存储在变量中。
  • 函数可以作为参数传递给另一个函数。
  • 函数可以返回它自己的函数。
  • 这些函数可以存储在列表、哈希表等数据结构中。

内部函数

内部函数,也称为嵌套函数,是在另一个函数内部声明的。外部作用域的变量可以被嵌套函数访问。内部函数的作用是保护它们免受函数外部发生的任何事情的影响。此过程的另一个名称是封装。

示例

输出

 
We are Learning Python from Javatpoint.   

说明

此 Python 代码演示了外部函数中的内部函数。由外部函数定义的内部函数打印传递给外部函数的 txt 参数。sometxt 是包含文本“We are Learning Python from Javatpoint.”的变量,并作为参数传递给 outerFunc,然后 outerFunc 调用 innerFunc 并打印结果。这证明了 Python 嵌套函数的概念。

由于 innerFunc() 是在 outerFunc() 中定义的,因此它是一个内部函数。在调用 innerFunc() 之前,我们需要先调用 outerFunc()。之后,由于 innerFunc() 已在其内部定义,outerFunc() 将调用 innerFunc()。

为了使内部函数运行,必须调用外部函数。为此,请参阅下面的示例。

输出

 
This code will return nothing when executed.   

说明

此 Python 代码定义的外部函数接受一个文本参数并在其中定义一个内部函数。内部函数打印外部函数的 text 变量。但是,当使用外部函数时,由于它是在没有任何打印语句或返回值的情况下调用的,因此不会产生明显的输出。

嵌套函数中的变量作用域

变量的作用域是我们可以在其中找到它并根据需要访问它的地方。

虽然在函数内访问全局变量是众所周知的,但访问函数外部的变量又如何呢?以这个例子为例。

输出

 
We are Learning Python from Javatpoint.   

说明

此 Python 代码中的 funcOne 函数有一个嵌套函数 funcTwo。词法作用域规则允许变量在 funcTwo 中可用,即使它是在 funcOne 中定义的。执行 funcOne 时,会调用 funcTwo 来打印 sometxt 的值,从而生成“We are Learning Python from Javatpoint.”的输出。

从上面的例子可以看出,它类似于使用函数检索全局变量。现在,假设您想修改外部函数的变量。

输出

 
I love Learning Python from Javatpoint.
We are Learning Python from Javatpoint.   

说明

此 Python 代码中的 funcOne 函数定义了一个名为 sometxt 的变量,其值为“We are Learning Python from Javatpoint.”。一个名为 funcTwo 的嵌套函数存在于 funcOne 中,它重新定义了 sometxt,意思是“I love Learning Python from Javatpoint.”。调用 funcTwo 时,会打印“I love Learning Python from Javatpoint.”作为 sometxt 的修改值。但是,当 funcOne 打印 sometxt 时,会打印“We are Learning Python from Javatpoint.”,指的是外部的 sometxt。正如可以观察到的,外部函数的变量值没有改变。

但是,外部函数的变量值是可以修改的。外部函数的变量可以通过多种不同的方式进行修改。

使用可迭代对象

输出

 
['I love Learning Python from Javatpoint.']
['I love Learning Python from Javatpoint.']   

说明

此 Python 代码中由 funcOne 函数初始化的列表 sometxt 只有一项,即“We are Learning Python from Javatpoint.”。一个嵌套函数 funcTwo 存在于 funcOne 中,它将 sometxt 的第一个元素更改为“I love Learning Python from Javatpoint.”。调用 funcTwo 时,会打印包含已修改元素的更新列表 sometxt。类似地,funcOne 在显示 sometxt 时显示更新列表中的已修改元素,这反映了 funcTwo 执行的更改。

使用 nonlocal 关键字

输出

 
I love Learning Python from Javatpoint.
I love Learning Python from Javatpoint.   

说明

此 Python 代码中的 sometxt 变量不是 funcTwo 函数的局部变量,而是属于外部函数 funcOne,如嵌套函数 funcTwo 中使用 nonlocal 关键字所示。这允许 funcTwo 修改 funcOne 定义的 sometxt 的值。当 funcTwo 将 sometxt 更改为“I love Learning Python from Javatpoint.”时,它还会影响 funcOne 中的 sometxt 值。结果,funcTwo 和 funcOne 都打印“I love Learning Python from Javatpoint.”作为 sometxt 的更新值。

值也可以被修改,如下面的示例所示。

输出

 
I love Learning Python from Javatpoint.
I love Learning Python from Javatpoint.   

说明

此 Python 代码中的 funcOne 函数定义了变量 funcOne.sometxt。使用点表示法(funcOne.sometxt)在嵌套函数 funcTwo 中访问并更改相同的变量 funcOne.s。因此,当 funcTwo 更改 funcOne.sometxt 为“I love Learning Python from Javatpoint.”时,funcOne 函数的 funcOne.sometxt 值也会被更新。因此,“I love Learning Python from Javatpoint.”是 funcOne 和 funcTwo 打印的 funcOne.sometxt 的更新值。

Python 闭包

当周围作用域中的值不在内存中时,闭包就是一个保留其内存的函数对象。

  • 它是一个保存函数及其周围环境的记录。具体来说,它是一个映射,将每个函数的自由变量——即在外部作用域中定义但在本地使用的变量——映射到闭包创建时绑定该名称的值或引用。
  • 与简单函数不同,闭包允许函数在超出其作用域时通过使用变量引用的副本或值来访问那些捕获的变量。

filter_none。

输出

 
Welcome to Javatpoint Python Tutorial   

说明

此 Python 代码中由 outer 函数声明的 inner 函数 innerFunc 打印在 outer 函数中定义的 sometxt 变量。在不调用内部函数(即不带括号)的情况下,外部函数返回内部函数。当调用 outerFunc 并将其分配给 funcOne 时,会捕获 sometxt 的值并创建闭包。稍后调用 funcOne 时,会生成“Welcome to Javatpoint Python Tutorial!”的输出。然后执行 innerFunc 函数,该函数仍然可以访问来自外部作用域的 text 变量。这说明了 Python 中的一个函数即使在外部函数完成运行后,仍然可以保留对其周围作用域中变量的访问。这称为闭包。

  • 闭包有助于在超出其作用域的情况下调用函数,如上面的代码所示。
  • 内部函数的范围仅限于外部函数。但是,通过使用闭包,我们可以轻松地扩展其范围以在外部调用函数。

输出

 
6
9
5
10   

说明

这个 Python 程序使用一个接受输入函数(add 或 sub)并输出一个名为 logFunction 的新函数的 logger 函数来演示闭包。在函数执行之前,logFunction 会记录函数名称及其参数。然后程序使用 logger 函数来构建加法和减法的 logger 例程(addLogger 和 subLogger)。这些 logger 函数演示了闭包的概念,其中内部函数(logFunction)通过在调用时记录函数名称和参数来保留对外部函数(logger)的变量(function_as_parameter, args)的访问。