Python基础:变量作用域与嵌套函数
文章目录
一、知识点详解
1.1 变量作用域
-
定义:变量在程序中可被访问的区域,分为
全局作用域
和局部作用域
。作用域类型 定义位置 访问范围 全局作用域 函数外部定义 整个程序 局部作用域 函数内部定义 仅在函数内部 -
示例:
global_var = "全局变量" # 全局作用域 def test_scope(): local_var = "局部变量" # 局部作用域 print(global_var) # 可访问全局变量 → "全局变量" test_scope() print(local_var) # ❌ 报错:NameError(无法访问局部变量)
1.2 全局变量与局部变量
-
1.2.1 访问与修改全局变量
直接访问:函数内部可直接读取全局变量。
修改全局变量:需使用global
关键字声明。count = 0 # 全局变量 def increment(): global count # 声明使用全局变量 count += 1 increment() print(count) # 1
-
1.2.2 变量优先级
当全局变量与局部变量同名时,在函数内部优先使用局部变量。x = "全局" def demo(): x = "局部" # 创建同名局部变量 print(x) # 输出:局部 demo() print(x) # 输出:全局
1.3 嵌套函数
-
1.3.1 嵌套函数基础
定义:在函数内部定义另一个函数,形成层级结构。
基础结构:def outer(): print("外部函数") def inner(): print("内部函数") inner() # 在外部函数内调用内部函数 outer() # 输出: # 外部函数 # 内部函数
-
1.3.2 访问外层变量
内部函数可读取外部函数的局部变量(但默认不可修改)。def outer(): outer_var = 10 def inner(): print(f"内部访问外部变量:{outer_var}") # 可读取 inner() outer() # 输出:内部访问外部变量:10
-
1.3.3 修改外层变量
注意:直接修改外层变量会创建新的局部变量。def outer(): counter = 0 def inner(): counter = 1 # 此时会创建新的局部变量counter,外层counter不变 # 若要修改外层counter,需使用nonlocal关键字声明 inner() print(counter) # 输出:0(未修改)
-
1.3.4
nonlocal
关键字
作用:允许内层函数修改外层函数的局部变量
(非全局变量)。
注意:nonlocal
只能修改外层函数的局部变量,若外层无对应变量会报SyntaxError
。def outer(): counter = 0 def inner(): nonlocal counter # 声明修改外层变量 counter += 1 inner() print(counter) # 输出:1 outer()
1.4 变量作用域规则(LEGB)
-
定义:Python按
L→E→G→B
顺序查找变量,即:
1. L(Local) :当前函数内的局部变量
2. E(Enclosing) :外层嵌套函数的局部变量
3. G(Global) :全局变量(模块级别)
4. B(Built-in) :内置函数(如print
,len
) -
说明示例:
x = "全局变量" # G层 def outer(): x = "外层变量" # E层 def inner(): x = "局部变量" # L层 print(x) # 输出:局部变量 inner() outer() print(x) # 输出:全局变量
1.5 LEGB
规则详解
-
1. Local(局部作用域)
函数内部定义的变量(含参数)
优先级最高,仅在函数内有效def func(): local_var = 10 print(local_var) # 10 func() print(local_var) # ❌ 报错:未定义
-
2. Enclosing(嵌套外层作用域)
外层嵌套函数的局部变量。
需用nonlocal
声明修改。def outer(): outer_var = 10 def inner(): nonlocal outer_var # 声明修改Enclosing层变量 outer_var += 1 inner() print(outer_var) # 11 outer()
-
3. Global(全局作用域)
模块级别定义的变量。
需用global
声明修改。global_var = 100 def update_global(): global global_var global_var = 200 update_global() print(global_var) # 200
-
4. Built-in(内置作用域)
Python预定义的函数和变量。
当其他层找不到时,最后查找内置层。def test_len(): # len = "局部变量" # 若取消注释,将覆盖内置len函数, 导致下方语句报错 print(len([1,2,3])) # 3 test_len()
-
总结表格
作用域层 定义位置 修改方式 生命周期 Local 函数内部 直接赋值 函数执行期间 Enclosing 外层嵌套函数 nonlocal
声明外层函数执行期间 Global 模块顶层 global
声明程序运行期间 Built-in Python内置 不可修改 解释器启动到关闭
二、说明示例
2.1 多层嵌套函数与LEGB规则应用
# 全局变量,处于G层
global_num = 100
def outer():
# 外层函数的局部变量,处于E层
outer_num = 20
def middle():
# 中间层函数的局部变量,处于E层(相对内层函数)
middle_num = 30
def inner():
# 内层函数的局部变量,处于L层
local_num = 40
# 按照LEGB规则,先查找L层,找到local_num
print(f"Local层变量: {local_num}")
# 查找E层,找到middle_num
print(f"Enclosing层(middle函数)变量: {middle_num}")
# 查找E层,找到outer_num
print(f"Enclosing层(outer函数)变量: {outer_num}")
# 查找G层,找到global_num
print(f"Global层变量: {global_num}")
nonlocal middle_num
middle_num += 1
return middle_num
result = inner()
print(f"修改后的middle_num: {result}")
middle()
outer()
2.2 使用 global
和 nonlocal
实现计数器
# 全局计数器
global_count = 0
def create_counter():
# 局部计数器
local_count = 0
def increment():
nonlocal local_count
local_count += 1
global global_count
global_count += 1
print(f"局部计数器: {local_count}, 全局计数器: {global_count}")
return local_count
return increment
# 创建计数器函数
counter = create_counter()
# 多次调用计数器函数
counter()
counter()
counter()
三、知识点总结
-
变量作用域:
全局作用域:函数外定义,全程序可访问;
局部作用域:函数内定义,仅限函数内访问。 -
全局与局部变量:
函数内可直接读取全局变量,修改需用global
声明;
存在同名变量时,局部变量优先于全局变量(函数内)。 -
嵌套函数:
函数内可定义子函数;
内部函数可读取外层函数变量,修改需用nonlocal
声明。 -
LEGB规则:
Python查找变量顺序:局部(L) → 嵌套外层(E) → 全局(G) → 内置(B)。 -
相似知识对比:
概念 核心规则 应用场景 全局作用域 函数外定义,全程序可见 全局配置、共享计数器 局部作用域 函数内定义,仅限函数内有效 临时计算、内部变量 global
修改全局变量 跨函数共享全局数据 nonlocal
修改嵌套外层函数的变量 嵌套函数中保留状态
四、扩展知识
4.1 规则验证函数
函数 | 作用 | 返回值类型 |
---|---|---|
locals() | 获取当前作用域的局部变量字典 | dict |
globals() | 获取当前作用域的全局变量字典 | dict |
说明示例:
# 全局作用域(G层)
global_var = "全局变量"
global_list = [1, 2, 3]
def outer():
# 外层函数局部作用域(E层)
outer_var = "外层变量"
def inner():
# 内层函数局部作用域(L层)
inner_var = "内层变量"
# 打印当前作用域的局部变量(L层)
print("\n--- 内层函数 locals() ---")
print(locals()) # 输出:{'inner_var': '内层变量', ...}
# 访问全局变量(通过 globals())
globals()["global_var"] = "全局变量(已修改)" # 修改全局变量
print("全局变量 global_var:", globals()["global_var"])
inner()
# 打印外层函数的局部变量(E层)
print("\n--- 外层函数 locals() ---")
print(locals()) # 输出:{'outer_var': '外层变量', 'inner': <function>}
# 调用外层函数
outer()
# 在全局作用域中打印 globals()
print("\n--- 全局作用域 globals() ---")
print("全局变量 global_list:", globals()["global_list"])
五、知识点考察题
x = 1
def outer():
x = 2
def middle():
x = 3
def inner():
nonlocal x
print(x)
inner()
middle()
print(x)
outer()
print(x)
以上代码三次打印输出分别是什么( ) ❓
- A.
3 3 3
- B.
3 3 1
- C.
3 2 1
- D.
3 2 3
答案:C
解析:
- 第一次打印在
inner()
函数中,nonlocal x
指向middle()
函数中的x=3
,故输出3
。 - 第二次打印在
outer()
函数中,其局部变量x=2
未被修改,故输出2
。 - 第三次打印在全局作用域,全局变量
x=1
未被修改,故输出1
。