闭包是一个函数对象,它不仅记住它的代码逻辑,还记住了定义它时的自由变量(即非全局也非局部,但被内部函数引用的变量)。即使外部函数已经执行完毕,这些自由变量的值仍然保存在内存中,可以通过闭包访问和使用。
当一个嵌套的函数引用了其外部函数中的变量,并且这个嵌套函数可以在其外部函数之外被调用时,就形成了一个闭包。
def outer_function(x):
def inner_function(y):
return x + y
return inner_function
closure = outer_function(10)
print(closure(5)) # 输出: 15
在这个例子中,inner_function
是 outer_function
的内部函数,并且引用了 outer_function
的参数 x
。当 outer_function
返回 inner_function
时,尽管 outer_function
已经执行结束,但是 inner_function
依然保留了对外部变量 x
的引用,这就形成了一个闭包。
闭包允许你在一个函数内创建并返回另一个函数,而后者能够“记住”前者内部的变量状态。这种特性对于需要保持某些状态的应用场景特别有用,比如计数器等。
def make_counter():
count = 0
def counter():
nonlocal count # 使用 nonlocal 声明 count 是外部函数中的变量
count += 1
return count
return counter
counter = make_counter()
print(counter()) # 输出: 1
print(counter()) # 输出: 2
print(counter()) # 输出: 3
在这个例子中,make_counter
函数返回了一个闭包 counter
,它可以不断增加并返回一个计数值。注意这里使用了 nonlocal
关键字来表明我们要修改的是外部函数中的 count
变量。
封装:闭包可以帮助我们封装一些数据,避免全局变量的污染。
状态保持:通过闭包,我们可以轻松地实现带有状态的函数。
减少命名冲突:由于闭包内部使用的变量对外部不可见,因此减少了命名冲突的风险。
闭包的一个常见应用场景就是作为装饰器的基础。装饰器本质上也是一个闭包,它接受一个函数作为输入,并返回一个新的函数,通常用于在不改变原函数的情况下添加额外的功能。
def decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@decorator
def say_hello():
print("Hello!")
say_hello()
输出:
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
可变对象:如果闭包中引用的对象是可以变的(如列表),那么对这个对象的任何更改都会反映在闭包中。
性能问题:虽然闭包很强大,但在某些情况下可能会导致性能问题或增加程序复杂度,所以应谨慎使用。
闭包是由函数及其相关引用环境组合而成的实体。
它允许函数“记住”并访问其定义范围内的变量,即使那个函数在其定义的作用域外被调用。
闭包广泛应用于各种编程模式中,如装饰器、工厂函数等。