【Python-Day 20】揭秘Python变量作用域:LEGB规则与global/nonlocal关键字详解
Langchain系列文章目录
01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
08-【万字长文】MCP深度解析:打通AI与世界的“USB-C”,模型上下文协议原理、实践与未来
Python系列文章目录
PyTorch系列文章目录
机器学习系列文章目录
深度学习系列文章目录
Java系列文章目录
JavaScript系列文章目录
Python系列文章目录
01-【Python-Day 1】告别编程恐惧:轻松掌握 Python 安装与第一个程序的 6 个步骤
02-【Python-Day 2】掌握Python基石:变量、内存、标识符及int/float/bool数据类型
03-【Python-Day 3】玩转文本:字符串(String)基础操作详解 (上)
04-【Python-Day 4】玩转文本:Python 字符串常用方法深度解析 (下篇)
05-【Python-Day 5】Python 格式化输出实战:%、format()、f-string 对比与最佳实践
06- 【Python-Day 6】从零精通 Python 运算符(上):算术、赋值与比较运算全解析
07-【Python-Day 7】从零精通 Python 运算符(下):逻辑、成员、身份运算与优先级规则全解析
08-【Python-Day 8】从入门到精通:Python 条件判断 if-elif-else 语句全解析
09-【Python-Day 9】掌握循环利器:for 循环遍历序列与可迭代对象详解
10-【Python-Day 10】Python 循环控制流:while 循环详解与 for 循环对比
11-【Python-Day 11】列表入门:Python 中最灵活的数据容器 (创建、索引、切片)
12-【Python-Day 12】Python列表进阶:玩转添加、删除、排序与列表推导式
13-【Python-Day 13】Python 元组 (Tuple) 详解:从创建、操作到高级应用场景一网打尽
14-【Python-Day 14】玩转Python字典(上篇):从零开始学习创建、访问与操作
15-【Python-Day 15】深入探索 Python 字典 (下):常用方法、遍历、推导式与嵌套实战
16-【Python-Day 16】代码复用基石:详解 Python 函数的定义与调用
17-【Python-Day 17】玩转函数参数(上):轻松掌握位置、关键字和默认值
18-【Python-Day 18】玩转函数参数(下):*args 与 **kwargs 终极指南
19-【Python-Day 19】函数的回响:深入理解 return
语句与返回值
20-【Python-Day 20】揭秘Python变量作用域:LEGB规则与global/nonlocal关键字详解
文章目录
- Langchain系列文章目录
- Python系列文章目录
- PyTorch系列文章目录
- 机器学习系列文章目录
- 深度学习系列文章目录
- Java系列文章目录
- JavaScript系列文章目录
- Python系列文章目录
- 前言
- 一、什么是变量作用域?
- 1.1 作用域的定义与意义
- 1.1.1 定义:变量的可见与可访问范围
- 1.1.2 意义:避免命名冲突、提高代码模块化和可读性
- 1.2 为什么需要理解作用域?
- 1.2.1 避免潜在的 Bug
- 1.2.2 写出更健壮、更易维护的代码
- 二、Python 的 LEGB 规则详解
- 2.1 L - Local (局部作用域)
- 2.1.1 定义与示例
- 2.1.2 局部变量的生命周期
- 2.2 E - Enclosing function locals (嵌套函数作用域/闭包作用域)
- 2.2.1 定义与示例
- 2.2.2 闭包的概念简介
- 2.3 G - Global (全局作用域)
- 2.3.1 定义与示例
- 2.3.2 全局变量的特点
- 2.4 B - Built-in (内置作用域)
- 2.4.1 定义与示例 (如 `len()`, `print()`)
- 2.4.2 内置作用域的普遍可用性
- 2.5 LEGB 查找顺序
- 2.5.1 由内向外的查找规则
- 三、改变作用域:`global` 与 `nonlocal` 关键字
- 3.1 `global` 关键字:在函数内部修改全局变量
- 3.1.1 为什么需要 `global`?
- 3.1.2 `global` 的使用方法与示例
- 3.1.3 注意事项与常见误区
- 3.2 `nonlocal` 关键字:在嵌套函数中修改外层非全局变量
- 3.2.1 为什么需要 `nonlocal`? (与 `global` 的区别)
- 3.2.2 `nonlocal` 的使用方法与示例
- 3.2.3 注意事项与适用场景
- 四、作用域应用的实际场景与最佳实践
- 4.1 场景一:模块化编程中的变量隔离
- 4.1.1 局部变量的优势
- 4.2 场景二:闭包的应用 (如计数器、状态保持)
- 4.2.1 使用嵌套作用域的巧妙之处
- 4.3 场景三:配置管理中的全局变量
- 4.3.1 合理使用全局变量
- 4.4 避免作用域相关的常见问题
- 4.4.1 局部变量覆盖全局变量 (UnboundLocalError)
- 4.4.2 滥用 `global` 和 `nonlocal`
- 五、总结
前言
在编程的世界里,变量是我们存储和操作数据的基本单元。然而,一个变量并非在代码的任何位置都可以被随意访问。它们有着自己的“势力范围”,这就是我们今天要探讨的主题——变量作用域(Variable Scope)。理解变量作用域对于编写出逻辑清晰、可维护性高且不易出错的 Python 代码至关重要。
Python 解释器在查找变量时,遵循一套特定的规则,这套规则被称为 LEGB 规则。本篇文章将带您深入剖析 LEGB 规则的每一个层面,并详细讲解如何在需要时使用 global
和 nonlocal
关键字来“跨越”作用域的界限。无论您是 Python 初学者还是有一定经验的开发者,相信本文都能帮助您更透彻地理解 Python 变量作用域的奥秘。
一、什么是变量作用域?
在正式学习 LEGB 规则之前,我们首先需要明确什么是变量作用域,以及为什么它如此重要。
1.1 作用域的定义与意义
1.1.1 定义:变量的可见与可访问范围
简单来说,变量作用域定义了一个变量在程序中能够被访问的区域。或者说,它规定了变量名的“可见性”和“生命周期”。在一个特定的作用域内定义的变量,通常只能在该作用域内部及其嵌套的子作用域中被直接访问。
1.1.2 意义:避免命名冲突、提高代码模块化和可读性
理解并正确使用作用域带来了诸多好处:
- 避免命名冲突:不同作用域中可以使用相同的变量名而不会相互干扰。例如,函数内部的局部变量
x
不会影响到全局作用域或其他函数中的同名变量x
。 - 增强代码模块化:函数可以将它们的变量“隐藏”在局部作用域中,只暴露必要的接口,这使得代码更加模块化,降低了不同部分代码之间的耦合度。
- 提高代码可读性和可维护性:清晰的作用域界限使得代码的逻辑更易于理解和追踪。当出现问题时,可以更快地定位到变量的定义和使用范围。
- 内存管理:局部变量通常在其作用域执行完毕后就会被销毁,有助于及时释放内存资源。
1.2 为什么需要理解作用域?
1.2.1 避免潜在的 Bug
对作用域理解不清是许多常见错误的根源。例如,试图在变量定义的作用域之外访问它,或者在函数内部无意中修改了全局变量,都可能导致 NameError
或 UnboundLocalError
等运行时错误,或者更隐蔽的逻辑错误。
1.2.2 写出更健壮、更易维护的代码
掌握作用域规则能让你更自信地组织代码结构,知道何时何地定义变量最为合适,以及如何安全地在不同代码块之间共享数据。这自然会引导你写出更健壮、更易于他人理解和维护的代码。
二、Python 的 LEGB 规则详解
Python 解释器在查找一个变量时,会按照特定的顺序搜索不同的作用域。这个搜索顺序就是著名的 LEGB 规则,它是以下四个作用域的缩写:
- Local (局部作用域)
- Enclosing function locals (嵌套函数作用域/闭包作用域)
- Global (全局作用域)
- Built-in (内置作用域)
解释器会从内到外,即按照 L -> E -> G -> B 的顺序查找变量。一旦找到,便停止搜索。如果遍历完所有作用域都未找到该变量,则会抛出 NameError
异常。
2.1 L - Local (局部作用域)
2.1.1 定义与示例
局部作用域(Local Scope)是指在函数内部定义的变量所处的作用域。这些变量通常被称为局部变量。它们只在函数被调用时创建,在函数执行完毕后销毁。
def my_function():x = 10 # x 是一个局部变量print(f"函数内部: x = {x}")my_function()
# print(x) # 这行会报错 NameError: name 'x' is not defined,因为 x 在函数外部不可见
在上面的例子中,变量 x
是在 my_function
函数内部定义的,因此它是一个局部变量。它只能在 my_function
函数内部被访问。当函数执行完毕后,x
的生命周期也就结束了。
2.1.2 局部变量的生命周期
- 创建:当函数被调用,且函数内部的变量赋值语句被执行时创建。
- 访问:只能在其定义的函数内部被访问。
- 销毁:当函数执行结束返回或抛出未处理的异常时,该函数内的局部变量通常会被销毁,其占用的内存空间会被回收。
2.2 E - Enclosing function locals (嵌套函数作用域/闭包作用域)
2.2.1 定义与示例
嵌套函数作用域(Enclosing function locals Scope),也常被称为闭包作用域,出现在当一个函数嵌套在另一个函数内部时。外层函数(Enclosing function)的局部作用域对于内层嵌套函数(Nested function)来说就是嵌套函数作用域。
内层函数可以访问外层函数的变量,但默认情况下不能直接修改它们(除非使用 nonlocal
关键字,后续会讲到)。
def outer_function():y = 20 # y 在 outer_function 的局部作用域,是 inner_function 的嵌套作用域变量def inner_function():# z = 30 # z 是 inner_function 的局部变量print(f"内层函数: y = {y}") # inner_function 可以访问 outer_function 中的 yinner_function()# print(z) # 这行会报错 NameError,因为 z 是 inner_function 的局部变量outer_function()
在这个例子中,inner_function
嵌套在 outer_function
内部。变量 y
是 outer_function
的局部变量。对于 inner_function
来说,变量 y
就位于其嵌套函数作用域中。因此,inner_function
可以读取 y
的值。
2.2.2 闭包的概念简介
当一个嵌套函数引用了其外部(但非全局)作用域中的变量,并且该嵌套函数被返回或传递到外部作用域之外时,就形成了一个闭包(Closure)。闭包会“记住”其创建时所处的环境,即使外层函数已经执行完毕,闭包仍然可以访问那些被引用的外部变量。
def greeter(name):# name 位于嵌套作用域def greet():print(f"Hello, {name}!") # greet 函数引用了外部的 name 变量return greet # 返回 greet 函数对象say_hello_to_bob = greeter("Bob")
say_hello_to_alice = greeter("Alice")say_hello_to_bob() # 输出: Hello, Bob!
say_hello_to_alice() # 输出: Hello, Alice!
即使 greeter("Bob")
执行完毕后,返回的 say_hello_to_bob
函数(即原来的 greet
函数)仍然能够访问到当时传入的 name
值 “Bob”。这是闭包的一个典型应用。
2.3 G - Global (全局作用域)
2.3.1 定义与示例
全局作用域(Global Scope)是指在模块(通常是一个 .py
文件)的顶层定义的变量所处的作用域。这些变量被称为全局变量。它们在整个模块的生命周期内都存在,并且可以在模块内的任何地方(包括所有函数内部)被访问(读取)。
global_var = 100 # global_var 是一个全局变量def show_global():print(f"函数内部访问全局变量: global_var = {global_var}")def try_modify_global():# global_var = 200 # 如果直接这样写,Python会认为你要创建一个新的局部变量 global_var# 如果之前没有 global_var += 1 这样的操作,而直接赋值,会创建局部变量# 如果之前有读取操作,再赋值,会引发 UnboundLocalErrorprint(f"尝试修改前: global_var = {global_var}") # 读取是允许的show_global()
try_modify_global()
print(f"模块顶层访问全局变量: global_var = {global_var}")
在上述代码中,global_var
在所有函数之外定义,因此它是一个全局变量。show_global
函数可以读取 global_var
的值。然而,在函数内部直接给全局变量赋新值需要特别注意,我们将在 global
关键字部分详细讨论。
2.3.2 全局变量的特点
- 定义位置:在 Python 文件的顶层,不属于任何函数。
- 可见性:在整个模块中都可见,包括模块内的所有函数。
- 生命周期:从被定义开始,直到程序(模块)执行结束。
- 修改限制:在函数内部,如果想修改全局变量的值,必须使用
global
关键字显式声明。如果仅是读取,则不需要。
2.4 B - Built-in (内置作用域)
2.4.1 定义与示例 (如 len()
, print()
)
内置作用域(Built-in Scope)是 Python 解释器启动时就自动加载的一个特殊作用域。它包含了所有 Python 的内置函数(如 len()
, print()
, str()
, list()
, type()
等)和内置常量(如 True
, False
, None
)以及内置异常类型。
这些内置名称在任何 Python 代码中都可以直接使用,无需导入或特别声明。
# 这些都是内置作用域的名称
print(len("hello")) # print 和 len 都是内置函数
print(True) # True 是内置常量
# my_variable = abs(-5) # abs 也是内置函数
2.4.2 内置作用域的普遍可用性
内置作用域是 LEGB 规则中查找的最后一层。这意味着,如果你定义了一个与内置名称相同的局部变量或全局变量,那么在该作用域内,你自定义的变量会**覆盖(shadow)**内置名称。
# 不推荐这样做,但可以演示覆盖效果
# str = "这是一个自定义的str变量" # 全局变量 str 覆盖了内置的 str() 类型转换函数
# print(str(123)) # TypeError: 'str' object is not callable# 恢复内置 str 函数 (通常重启解释器或删除自定义变量)
# del strdef my_func():len = lambda x: "Haha, I am a fake len!" # 局部 len 覆盖了内置 len()print(len("test"))my_func() # 输出: Haha, I am a fake len!
print(len("real test")) # 输出: 9 (函数外部的 len 仍然是内置的)
因此,通常建议避免使用与内置名称相同的自定义变量名,以防止混淆和潜在的错误。
2.5 LEGB 查找顺序
2.5.1 由内向外的查找规则
当 Python 代码中引用一个变量名时,解释器会严格按照 L -> E -> G -> B 的顺序去查找这个名称:
- L (Local): 首先在当前函数(或代码块)的局部作用域中查找。如果找到,停止搜索并使用该变量。
- E (Enclosing function locals): 如果在局部作用域中没有找到,并且当前函数嵌套在其他函数中,则在外层函数的局部作用域中查找。这个查找会逐层向上进行,直到最外层的非全局函数。如果找到,停止搜索。
- G (Global): 如果在所有嵌套作用域中都未找到,则在模块级别的全局作用域中查找。如果找到,停止搜索。
- B (Built-in): 如果全局作用域中也未找到,则最后在内置作用域中查找。如果找到,停止搜索。
- NameError: 如果遍历完所有 LEGB 作用域后仍然没有找到该名称,Python 解释器会引发
NameError
异常。
三、改变作用域:global
与 nonlocal
关键字
在某些情况下,我们可能需要在函数内部修改定义在外部作用域的变量。Python 提供了两个关键字来实现这一目标:global
和 nonlocal
。
3.1 global
关键字:在函数内部修改全局变量
3.1.1 为什么需要 global
?
默认情况下,如果在函数内部对一个变量进行赋值操作,Python 会认为你正在创建一个新的局部变量,即使在全局作用域中已经存在一个同名变量。如果此时你试图在赋值之前读取该变量(例如 x = x + 1
),Python 会因为找不到已定义的局部变量 x
而抛出 UnboundLocalError
。
如果你确实希望在函数内部修改全局变量的值,而不是创建一个同名的局部变量,就需要使用 global
关键字。
3.1.2 global
的使用方法与示例
global
关键字用于在函数内部声明一个或多个变量是全局变量。声明之后,对这些变量的赋值操作就会直接修改全局作用域中的对应变量。
count = 0 # 全局变量def increment_global_counter():global count # 声明 count 是全局变量count += 1 # 现在修改的是全局 countprint(f"函数内部: count = {count}")print(f"调用前: count = {count}") # 输出: 调用前: count = 0
increment_global_counter() # 输出: 函数内部: count = 1
print(f"调用后: count = {count}") # 输出: 调用后: count = 1
在 increment_global_counter
函数中,通过 global count
声明,后续的 count += 1
操作修改的是全局变量 count
。
3.1.3 注意事项与常见误区
- 声明位置:
global
声明必须在对该变量进行任何赋值或修改操作之前。通常放在函数体的开头。 - 仅用于修改:如果只是读取全局变量的值,不需要使用
global
关键字。version = "1.0" def get_version():# global version # 读取时不需要 globalreturn version print(get_version()) # 输出: 1.0
- 多个变量:可以在一个
global
语句中声明多个全局变量,用逗号隔开:global x, y, z
。 - 避免滥用:过度使用全局变量会降低代码的模块化程度和可读性,使得程序状态难以追踪。应尽量通过函数参数和返回值来传递数据,而不是依赖全局变量。
3.2 nonlocal
关键字:在嵌套函数中修改外层非全局变量
3.2.1 为什么需要 nonlocal
? (与 global
的区别)
nonlocal
关键字用于在嵌套函数(内部函数)中修改其直接外层函数(Enclosing function)中定义的变量,但这个外层变量不能是全局变量。
global
用于函数内部修改模块级别的全局变量。nonlocal
用于嵌套函数内部修改其直接外层函数的局部变量(即E层作用域的变量)。
如果没有 nonlocal
,在内层函数中对与外层函数同名的变量进行赋值,同样会被视为创建了一个新的内层函数的局部变量。
3.2.2 nonlocal
的使用方法与示例
nonlocal
声明一个或多个变量是来自最近的封闭作用域(不包括全局作用域)的变量。
def outer_func():x = 10 # x 是 outer_func 的局部变量,是 inner_func 的嵌套作用域变量def inner_func():nonlocal x # 声明 x 是来自外层函数 outer_func 的变量x += 5 # 修改的是 outer_func 中的 xprint(f"内层函数: x = {x}")print(f"调用内层函数前: x = {x}") # 输出: 调用内层函数前: x = 10inner_func() # 输出: 内层函数: x = 15print(f"调用内层函数后: x = {x}") # 输出: 调用内层函数后: x = 15outer_func()
在 inner_func
中,nonlocal x
使得 x += 5
修改了 outer_func
中的 x
。
3.2.3 注意事项与适用场景
- 声明位置:与
global
类似,nonlocal
声明也应在对变量进行赋值或修改之前。 - 作用域限制:
nonlocal
只能用于嵌套函数中,并且它引用的变量必须存在于其直接或间接的某个外层函数作用域中,但不能是全局作用域。如果Python在向外查找时,直到全局作用域才找到同名变量,或者根本没找到,都会报错。 - Python 3 引入:
nonlocal
是在 Python 3 中引入的关键字。 - 主要用途:常用于实现闭包中需要修改状态的场景,或者在复杂的嵌套函数结构中管理状态。
def counter_factory():count = 0 # 嵌套作用域变量def increment():nonlocal countcount += 1return countreturn incrementmy_counter = counter_factory()
print(my_counter()) # 输出: 1
print(my_counter()) # 输出: 2
在这个闭包实现的计数器中,nonlocal count
确保了每次调用 increment
时,修改的都是 counter_factory
作用域中的那个 count
变量。
四、作用域应用的实际场景与最佳实践
理解了 LEGB 规则以及 global
和 nonlocal
的用法后,我们来看看它们在实际编程中的应用和一些最佳实践。
4.1 场景一:模块化编程中的变量隔离
4.1.1 局部变量的优势
函数是模块化编程的基本单元。将变量限制在函数的局部作用域内,可以:
- 减少副作用:函数的操作不会意外修改函数外部的变量。
- 提高复用性:函数不依赖于外部特定状态(除非通过参数传入),更容易在不同上下文中复用。
- 简化测试:测试函数时,只需关注其输入和输出,不必担心全局状态的影响。
def process_data(data_list):processed_count = 0 # 局部变量,不会影响外部result = []for item in data_list:# ... 一些处理逻辑 ...processed_count += 1result.append(item * 2) # 假设的处理print(f"处理了 {processed_count} 个项目。")return resultmy_data = [1, 2, 3]
processed_my_data = process_data(my_data)
# processed_count 在这里是不可见的,也不会被 process_data 函数影响
4.2 场景二:闭包的应用 (如计数器、状态保持)
4.2.1 使用嵌套作用域的巧妙之处
闭包利用了嵌套作用域的特性,允许内部函数“记住”并访问其创建时外部环境中的变量,即使外部函数已经执行完毕。这在需要保持状态或创建带有私有数据的函数时非常有用。
前面提到的计数器 counter_factory
就是一个很好的例子。其他应用还包括:
- 延迟计算:创建一个函数,其行为由创建时的参数决定。
- 回调函数:创建需要特定上下文信息的回调。
- 装饰器:装饰器本身就是一种广泛利用闭包和嵌套函数的技术(我们将在后续文章中详细介绍)。
4.3 场景三:配置管理中的全局变量
4.3.1 合理使用全局变量
虽然通常建议限制全局变量的使用,但在某些情况下,它们是合理的,例如:
- 模块级别的常量:如
PI = 3.14159
,或者一些配置参数(如DEBUG_MODE = True
)。这些通常用全大写字母命名,以表示其常量性质。 - 应用范围的单例对象:例如数据库连接池或日志记录器实例,它们在整个应用程序生命周期中通常只需要一个。
最佳实践:
- 尽量将全局变量定义在模块的顶部。
- 使用有意义且不易冲突的名称。
- 对于可配置的全局变量,考虑使用专门的配置模块或配置文件,而不是散布在代码各处。
- 如果函数需要修改全局变量,务必使用
global
关键字,并清晰注释其原因。
4.4 避免作用域相关的常见问题
4.4.1 局部变量覆盖全局变量 (UnboundLocalError)
当你在函数内部尝试修改一个与全局变量同名的变量,但没有使用 global
声明时,Python 会创建一个新的局部变量。如果在赋值之前就尝试读取它(例如 x = x + 1
,其中 x
是全局变量),就会触发 UnboundLocalError: local variable 'x' referenced before assignment
。
my_global_var = 50def problematic_function():# 错误演示: UnboundLocalError# print(my_global_var) # 如果只有这一行,可以正常读取全局变量my_global_var = my_global_var + 10 # Python 认为 my_global_var 是局部变量,但右侧读取时它还未赋值print(my_global_var)# problematic_function() # 取消注释会报错def correct_function():global my_global_varmy_global_var = my_global_var + 10print(my_global_var)correct_function() # 输出: 60
解决方法:
- 如果意图是修改全局变量,使用
global
关键字。 - 如果意图是使用全局变量的值来计算新的局部变量,确保赋值语句的右侧使用的是明确的全局变量(如果需要),或者将全局变量作为参数传递给函数。
4.4.2 滥用 global
和 nonlocal
过度使用 global
和 nonlocal
会使代码的 数据流变得复杂和难以追踪,破坏封装性,增加调试难度。
最佳实践:
- 优先使用参数传递和返回值:这是函数间数据交换最清晰、最推荐的方式。
- 限制
global
的使用:仅在确实需要在函数内修改全局状态,且没有更好替代方案时使用。通常用于模块级别的配置或状态。 - 谨慎使用
nonlocal
:nonlocal
主要用于闭包和较复杂的嵌套函数结构。如果发现嵌套层级过深或nonlocal
使用频繁,可能需要重新审视函数设计。
五、总结
变量作用域和 LEGB 规则是 Python 编程中非常核心的概念。深刻理解它们有助于我们编写出更高效、更健壮、更易于维护的代码。
在本篇文章中,我们详细探讨了:
- 变量作用域的定义与重要性:它决定了变量的可见范围,有助于避免命名冲突,增强代码模块化。
- Python 的 LEGB 规则:
- L (Local):函数内部定义的变量。
- E (Enclosing function locals):嵌套函数中,外层函数的变量。
- G (Global):模块顶层定义的变量。
- B (Built-in):Python 解释器预定义的名称。
- 查找顺序是 L -> E -> G -> B。
global
关键字:用于在函数内部声明并修改全局作用域的变量。nonlocal
关键字:用于在嵌套函数内部声明并修改其直接外层(非全局)函数的变量,常用于闭包。- 作用域的应用场景与最佳实践:包括模块化编程中的变量隔离、闭包的应用、合理使用全局变量以及避免常见的
UnboundLocalError
和滥用global
/nonlocal
的问题。
掌握了这些知识,你就能更好地理解 Python 代码中变量是如何被查找和使用的,从而更自信地驾驭 Python 编程。在后续的学习和实践中,请多加留意变量的作用域,这将使你的 Python 之旅更加顺畅!