跳到主要内容

Python 闭包

提示
  1. 闭包定义:Python中的闭包是一种特殊的嵌套函数,能够在其外部函数已经结束后仍然访问外部函数的变量。
  2. 工作原理:闭包通过返回一个内部函数来实现,这个内部函数可以访问并保持外部函数的局部变量,即使外部函数已经执行完毕。
  3. 使用场景:闭包适合于简化代码,隐藏数据,并避免使用全局变量,特别适用于需要封装少量方法的小型任务。对于更复杂的情况,使用类可能更合适。

Python闭包是一个嵌套函数,它允许我们在外部函数关闭后仍然访问外部函数的变量。

在我们学习闭包之前,让我们先回顾一下Python中嵌套函数的概念。

Python中的嵌套函数

在Python中,我们可以在另一个函数内创建一个函数。这被称为嵌套函数。例如,

def greet(name):
# 内部函数
def display_name():
print("Hi", name)

# 调用内部函数
display_name()

# 调用外部函数
greet("John")

# 输出: Hi John

在上面的例子中,我们在greet()函数内定义了display_name()函数。

这里,display_name()是一个嵌套函数。嵌套函数的工作方式类似于普通函数。它在greet()函数内调用display_name()时执行。

Python闭包

正如我们已经讨论过的,闭包是一个嵌套函数,它帮助我们即使在外部函数关闭后也能访问外部函数的变量。例如,

def greet():
# 在内部函数外定义的变量
name = "John"

# 返回一个嵌套的匿名函数
return lambda: "Hi " + name

# 调用外部函数
message = greet()

# 调用内部函数
print(message())

# 输出: Hi John

在上面的例子中,我们创建了一个名为greet()的函数,它返回一个嵌套的匿名函数

这里,当我们调用外部函数,

message = greet()

返回的函数现在赋值给了message变量。

此时,外部函数的执行已经完成,所以name变量应该被销毁。然而,当我们使用

print(message())

调用匿名函数时,我们能够访问外部函数的name变量。

这是可能的,因为嵌套函数现在作为一个闭包,即使在外部函数执行后,也将外部作用域变量封闭在其作用域内。

让我们看一个更清晰的例子。

示例:使用Python闭包打印奇数

def calculate():
num = 1
def inner_func():
nonlocal num
num += 2
return num
return inner_func

# 调用外部函数
odd = calculate()

# 调用内部函数
print(odd())
print(odd())
print(odd())

# 再次调用外部函数
odd2 = calculate()
print(odd2())

输出

3
5
7
3

在上面的例子中,

odd = calculate()

这段代码执行了外部函数calculate()并返回了一个奇数闭包。

这就是为什么我们即使在外部函数完成后也能访问calculate()的num变量。

再次,当我们使用

odd2 = calculate()

调用外部函数时,返回了一个新的闭包。因此,当我们调用odd2()时,我们再次得到3

何时使用闭包?

那么闭包有什么用处呢?

闭包可以用来避免全局变量,并提供数据隐藏,对于只有一个或几个方法的简单情况,可以是一个优雅的解决方案。

然而,对于具有多个属性和方法的较大案例,类实现可能更合适。

def make_multiplier_of(n):
def multiplier(x):
return x * n
return multiplier

# 3的乘数
times3 = make_multiplier_of(3)

# 5的乘数
times5 = make_multiplier_of(5)

# 输出: 27
print(times3(9))

# 输出: 15
print(times5(3))

# 输出: 30
print(times5(times3(2)))

Python装饰器也广泛使用闭包。

最后,值得指出的是,闭包函数中封闭的值是可以找出来的。

所有函数对象都有一个__closure__属性,如果它是一个闭包函数,它会返回一个单元格对象的元组。

根据上面的例子,我们知道times3times5是闭包函数。