Python 闭包详解:原理、创建条件与实际应用场景

小岛来信
小岛来信
发布时间:2026-10-13| 3人浏览过
原创

本文深入解析 Python 闭包的创建原理与使用方法。通过嵌套函数与非局部变量的概念,阐述闭包如何在不使用全局变量的情况下实现数据隐藏。文章详细列出创建闭包的三个必要条件,并探讨其在类方法较少时的优雅替代方案,以及作为 Python 装饰器核心机制的重要应用。

Python 闭包的使用方法

嵌套函数中的非局部变量

在深入探讨闭包之前,需要先理解嵌套函数和非局部变量这两个核心概念。

嵌套函数是指在另一个函数内部定义的函数。这种内部函数有权访问其外层函数作用域内的变量。

在 Python 中,默认情况下这些非局部变量只能被读取。若要在嵌套函数中修改外层函数的变量,必须使用 `nonlocal` 关键字显式声明。

以下是访问非局部变量的嵌套函数示例。

def print_msg(msg):
# This is the outer enclosing function

  def printer():
# This is the nested function
    print(msg)

  printer()

# We execute the function
# Output: Hello
print_msg("Hello")

从代码可以看出,嵌套函数 `printer()` 成功访问了外层函数 `print_msg()` 中的非局部变量 `msg`。

定义闭包函数

如果修改上述示例,让 `print_msg()` 函数最后一行返回 `printer` 函数对象本身而不是调用它,结果会如何?定义方式如下所示:

def print_msg(msg):
# This is the outer enclosing function

  def printer():
# This is the nested function
    print(msg)

  return printer # this got changed

# Now let's try calling this function.
# Output: Hello
another = print_msg("Hello")
another()

这种写法看似不寻常,但揭示了闭包的本质。

当使用字符串“Hello”调用 `print_msg()` 时,返回的函数被赋值给另一个变量。即使 `print_msg()` 的执行已经结束,调用该返回函数(如 `another()`)时,它依然能记住并访问当初传入的消息。

这种将数据(如“Hello”)附加到代码执行环境中的技术,在 Python 中被称为闭包。

即使外层变量已经超出作用范围,或者外层函数本身已从当前命名空间中删除,闭包仍能保留并访问其封闭范围内的值。

你可以在 Python 交互环境中尝试以下代码以验证输出结果。

>>> del print_msg
>>> another()
Hello
>>> print_msg("Hello")
Traceback (most recent call last):
...
NameError: name 'print_msg' is not defined

什么时候形成闭包?

通过上述示例可以看出,当嵌套函数引用了其封闭作用域内的值时,Python 便形成了一个闭包。

在 Python 中创建有效的闭包必须满足以下三个标准:

  • 必须存在一个嵌套函数(即函数内部定义的函数)。
  • 嵌套函数必须引用封闭函数中定义的值(非局部变量)。
  • 闭包函数必须返回该嵌套函数。

何时使用闭包?

那么,闭包的优势究竟在哪里?

闭包能够有效避免使用全局变量,并提供一定程度的数据隐藏。此外,它还能提供一种面向对象的解决方案。

当类中仅包含极少的方法(通常只有一种方法)时,使用闭包可以提供一个更简洁、优雅的替代方案。然而,如果类的属性和方法数量较多,则实现一个完整的类更为合适。

这是一个简单的示例,展示了在特定场景下闭包比定义类和创建对象更具优先级的情况。

 
def make_multiplier_of(n):
  def multiplier(x):
    return x * n
  return multiplier

# Multiplier of 3
times3 = make_multiplier_of(3)

# Multiplier of 5
times5 = make_multiplier_of(5)

# Output: 27
print(times3(9))

# Output: 15
print(times5(3))

# Output: 30
print(times5(times3(2)))

Python 中的装饰器也广泛使用了闭包机制。值得注意的是,装饰器内部可以访问封闭函数中包含的值。

所有函数对象都拥有一个 `__closure__` 属性。如果该函数是闭包,此属性将返回一个包含单元格对象(cell object)的元组。参考前文示例,我们知道 `times3` 和 `times5` 均为闭包函数。

>>> make_multiplier_of.__closure__
>>> times3.__closure__
(<cell at 0x0000000002D155B8: int object at 0x000000001E39B6E0>,)

单元格(cell)对象具有一个名为 `cell_contents` 的属性,用于存储闭包中的值。

>>> times3.__closure__[0].cell_contents
3
>>> times5.__closure__[0].cell_contents
5

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。