一、nonlocal
和 global
的区别
作用范围
global
:用于在函数内部声明一个变量是全局变量。如果在函数中使用global
关键字声明了某个变量,那么在函数内部对该变量的操作,就是对全局作用域中这个变量的操作。例如:
python
count = 10
def modify_count():
global count
count = 20
print(count)
modify_count() # 输出 20
print(count) # 输出 20,全局变量count已经被修改
nonlocal
:用于在嵌套函数中,声明一个变量不是当前函数的局部变量,而是来自外层(非全局)函数的变量。它使得内层函数可以修改外层函数中定义的变量,前提是外层函数中没有使用global
声明这个变量。比如:
python
def outer():
num = 5
def inner():
nonlocal num
num = 10
print(num)
inner()
print(num)
outer()
# 输出 10
# 输出 10,因为内层函数通过nonlocal修改了外层函数的num变量
适用场景
global
:当需要在函数内部修改全局作用域中的变量时使用。nonlocal
:在函数嵌套的场景下,内层函数想要修改外层函数中定义的变量,且该变量不是全局变量时使用。
二、闭包的作用
数据隐藏与封装
闭包可以将一些数据(即外层函数的变量)与操作这些数据的函数绑定在一起,形成一个相对独立的单元,外界不能直接访问这些被 "隐藏" 的数据,只能通过闭包返回的函数来操作。例如,实现一个简单的计数器:
python
def counter():
count = 0
def increment():
nonlocal count
count += 1
return count
return increment
count_func = counter()
print(count_func()) # 输出 1
print(count_func()) # 输出 2
print(count_func()) # 输出 3
在这个例子中,count
变量被隐藏在闭包内部,外界无法直接访问和修改,只能通过 increment
函数来对其进行递增操作,实现了数据的封装。
状态保持
闭包可以 "记住" 外层函数执行时的变量状态,方便在多次调用返回的函数时,基于之前的状态进行操作。比如模拟一个累加器:
python
def accumulator(initial_value=0):
def accumulate(num):
nonlocal initial_value
initial_value += num
return initial_value
return accumulate
acc = accumulator(5)
print(acc(3)) # 输出 8,初始值5加上传入的3
print(acc(2)) # 输出 10,基于上一次结果8再加上传入的2
这里闭包记住了 initial_value
的状态,每次调用 accumulate
函数时,都是基于上一次的状态进行累加操作。
函数复用
闭包可以创建具有特定初始状态的函数,方便在不同场景下复用。比如创建不同税率的计算函数:
python
def tax_calculator(tax_rate):
def calculate_tax(amount):
return amount * tax_rate
return calculate_tax
calculate_sales_tax = tax_calculator(0.08) # 8% 的销售税
calculate_income_tax = tax_calculator(0.2) # 20% 的所得税
print(calculate_sales_tax(100)) # 输出 8
print(calculate_income_tax(1000)) # 输出 200
通过 tax_calculator
函数创建不同税率的计算函数,这些函数都能复用内部计算逻辑,只是初始的税率不同。
三、注意
在 Python 中,内部函数本来就可以 "读取" 外层函数的变量(包括参数),但只有通过 nonlocal
声明后,才能 "修改" 外层函数的变量。