python中的闭包相关知识点

闭包

闭包的定义

闭包 = 函数 + 环境,具体来说:

  1. 外层函数定义了局部变量

  2. 内层函数引用了这些外层变量

  3. 外层函数返回内层函数的引用

这种结构使得外层函数的局部变量生命周期被延长,即使外层函数已经执行完毕。

闭包的三要素(特点):

1:有嵌套:外部函数嵌套内部函数

2:有引用:内部函数引用外部函数变量

3:有返回:外部函数中,返回内部函数的函数名

关于外部函数的变量有两类:

1、外部函数(局部)变量

2、外部函数名(形参列表)的形参列表也是

基础示例

def outer():
    x = 10          # 外层函数的局部变量
    def inner():     # 内层函数
        print(x)    # 引用外层变量
    return inner     # 返回内层函数引用

closure = outer()    # 此时 outer() 已执行完毕
closure()            # 输出 10 → 仍然能访问到已消亡的 x
关键现象:
  • 外层函数 outer 执行完毕后,其局部变量 x 本应被销毁

  • 但由于内层函数 inner 引用了 x,Python 会保持这个变量的存活

nonlocal关键字

为什么需要 nonlocal

Python 的变量作用域遵循 LEGB 规则

  • Local(局部作用域)

  • Enclosing(闭包作用域)

  • Global(全局作用域)

  • Built-in(内置作用域)

当在内层函数中 赋值 一个变量时,Python 会默认将其视为 局部变量。如果外层作用域有同名变量,内层的赋值操作会 遮盖(Shadow) 外层变量,导致无法直接修改外层变量。

nonlocal 的作用

通过 nonlocal 声明变量,可以明确告诉解释器:

“这个变量不是局部的,请去外层作用域查找并修改它。

nonlocal vs global

python中的闭包相关知识点_第1张图片

nonlocal 的核心规则

必须存在外层变量

逐层向外查找

def outer():
    x = 1
    def middle():
        x = 2
        def inner():
            nonlocal x  # 修改 middle() 中的 x
            x = 3
        inner()
        print(x)  # 3
    middle()
    print(x)  # 1(outer 的 x 未被修改)
outer()

不能指向全局变量

闭包的内存模型

def counter():
    count = 0
    def increment():
        nonlocal count
        count += 1
        return count
    return increment

c1 = counter()  # 创建第一个闭包
print(c1())     # 1
print(c1())     # 2

c2 = counter()  # 创建第二个闭包(独立环境)
print(c2())     # 1
c1 ──→ increment 函数对象
         ↑
         ├─ __closure__ 属性
         ↓ 
         cell 对象 → count=2

c2 ──→ increment 函数对象
         ↑
         ├─ __closure__ 属性
         ↓ 
         cell 对象 → count=1

闭包与类的对比

python中的闭包相关知识点_第2张图片

eg:

编写一个闭包函数 counter,它返回一个内部函数 increment。每次调用 increment 时,它会增加并返回一个计数器。使用 nonlocal 关键字来实现。

def counter():
    count = 0
    def increment():
        nonlocal count
        count += 1
        return count
    return increment

if __name__ == '__main__':
    inc = counter()
    print(inc())
    print(inc())
    print(inc())

你可能感兴趣的:(python,开发语言)