闭包(Closure)是指一个函数记住了并可以访问它的词法作用域(lexical scope),即使这个函数在词法作用域之外执行。
闭包其实就是延伸了作用域的函数,包括被延伸函数主体中引用的非全局变量和局部变量。这些变量必须来自包含被延伸函数的外部函数的局部作用域。函数是不是匿名的没有关系,关键是它能访问主体之外定义的非全局变量。
闭包常用于创建私有变量、函数工厂等场景。装饰器本质上也是闭包的一种应用。
闭包由以下两部分组成:
一个嵌套的函数(内部函数)。
这个嵌套函数引用了其外部作用域中的变量,并且在其外部作用域不再存在的情况下依然能够访问这些变量。
series 是 自由变量 (free variable)。自由变量指未在局部作用域中绑定的变量。
def make_averager(): #外部函数
series = [] #变量
def averager(new_value): #内部函数
series.append(new_value) #内部函数引用了变量series
total = sum(series)
return total / len(series)
return averager #外部函数返回内部函数,此时averager就成为了一个闭包,因为它技术了并可以访问外部函数make_averager
# 创建闭包
avg = make_averager()
# 调用闭包,实际上是在调用内部函数averager,此时averager依然可以访问外部函数的值
a=avg(10)
print(a)
b=avg(19)
print(b)
私有变量
闭包可以用来模拟私有变量,因为外部无法直接访问内部函数的变量。
nonlocal关键字的作用是把变量标记为自由变量,即便在函数中为变量赋予了新值。如果为 nonlocal 声明的变量赋予新值,那么闭包中保存的绑定也会随之更新。
def make_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
counter = make_counter()
print(counter()) # 输出: 1
print(counter()) # 输出: 2
#计算累计平均值,不保存所有历史
def make_averager():
count = 0
total = 0
def averager(new_value):
nonlocal count, total
count += 1
total += new_value
return total / count
return averager
avg = make_averager()
a=avg(10)
print(a)
b=avg(80)
print(b)
函数工厂
闭包可以用来创建参数化的函数。
def make_multiplier(factor):
def multiplier(number):
return number * factor
return multiplier
double = make_multiplier(2)
triple = make_multiplier(3)
print(double(5)) # 输出: 10
print(triple(5)) # 输出: 15
装饰器
def my_decorator(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
result = func(*args, **kwargs)
print(f"{func.__name__} returned {result}")
return result
return wrapper
@my_decorator
def say_hello():
return "Hello!"
print(say_hello())