“闭包”这个术语是从函数式编程中借来的,早在 Python 出现之初就已存在。闭包允许函数记住它们创建时的环境,即使它们在外部环境中被调用。这个概念提供了灵活性,并允许实现多种模式,包括函数工厂和惰性计算。
在 Python 中,函数是第一类对象。有时需要内部函数在外部函数完成后仍然使用 enclosing 作用域中的变量。普通的词法作用域在函数返回时并不保证这样的行为。如果这样的函数访问了它创建时的环境变量,就会产生闭包。
当内函数引用外函数定义的变量,而外函数返回了内函数时,就会产生闭包。这通常用于创建函数工厂、在不使用类的情况下封装状态,以及构造具有“就地”参数的函数。
def make_multiplier(factor): def multiplier(x): return x * factor return multiplier mul2 = make_multiplier(2) mul3 = make_multiplier(3) print(mul2(10)) # 20 print(mul3(10)) # 30
nonlocal。如果变量在内函数内部被修改,闭包能否在调用之间保持可变状态?
是的,如果在内函数中使用 nonlocal 关键字。如果没有 nonlocal,赋值会创建一个新的局部变量,而不更改外部变量。
def counter(): count = 0 def inc(): nonlocal count count += 1 return count return inc c = counter() print(c()) # 1 print(c()) # 2
在 Python 中,是否可以利用闭包实现私有变量,而不是使用类?
是的,闭包提供了一种简单的实现“私有”变量的方法,这些变量在没有内函数的 getter/setter 时对外不可及。
闭包是否只应用于函数?在 Python 中可以使用 lambda 函数构造闭包吗?
是的,闭包也可以由 lambda 表达式形成,因为它们在词法变量绑定方面与 def 相似。
def make_power(n): return lambda x: x ** n square = make_power(2) cube = make_power(3) print(square(4)) # 16 print(cube(2)) # 8
nonlocal 的情况下自动更改外部变量。一个在循环中形成处理程序的函数工厂在闭包中使用循环变量:
handlers = [] for i in range(3): def handler(x): return x + i handlers.append(handler) print([h(10) for h in handlers]) # [12, 12, 12]
优点:
缺点:
i,它的最后值是 2 — 对大多数人来说这种行为是意料之外的。使用默认参数来“固定”值:
handlers = [] for i in range(3): def handler(x, j=i): return x + j handlers.append(handler) print([h(10) for h in handlers]) # [10, 11, 12]
优点:
缺点: