上述代码定义了一个test()函数,使用一个变量func_obj保存了test()函数的引用(注意test不要加(),否则func_obj保存的是test()函数的返回值)
此时func_obj保存了test()函数的引用,即func_obj指向了test()函数的代码块在内存中的地址,此时对func_obj进行调用,就是对func_obj所指向的代码块进行调用
可以看到,调用func_obj()后打印了“这是 test 函数的内部代码…”
id()函数可以返回对象的唯一标识符,即对象的内存地址,使用id()函数可以查看此时test()函数和变量func_obj的内存地址
def test():print('这是 test 函数的内部代码...')func_obj = testfunc_obj()print(id(test))print(id(func_obj)) 这是 test 函数的内部代码...14206570214241420657021424 可以看到此时test()函数和变量func_obj指向同一个内存地址什么是闭包 在一些程序设计语言(例如Python)中,在函数中可以嵌套定义另一个函数,如果内部的函数引用了外部函数的变量,并且外部函数的返回值是内部函数的引用,此时被返回的内部函数引用称为闭包换句话说就是,当内部函数的引用被作为返回值返回时,携带了外部函数的变量的信息,就形成了一个闭包
闭包示例 def test(num):def wrapper():print(num)return wrapperfunc_obj = test(0)func_obj() 0 上述代码在test()函数的内部定义了wrapper()函数,wrapper()函数引用了外部函数test()的变量num,test()将wrapper()函数的引用作为返回值返回由于wrapper()函数引用了test()的变量num,调用test(0)时,test()函数将wrapper()函数的引用作为返回值返回的同时携带了变量num的信息然后调用func_obj(),打印了 0 0 0,此时运行了print(num)即print(0) 闭包的本质 函数在调用结束后,其参数和局部变量会被内存回收机制回收,无法再被访问闭包携带了包含它的函数的局部变量等信息,实际上是使包含它的函数的作用域在调用后不被内存回收机制所回收而保存在内存中,使闭包能够访问到这些局部变量等信息 闭包带来的问题 由于闭包会携带包含它的函数的作用域,因此会比普通函数占用更多的内存
使用闭包修改外部函数中的变量 def counter(cnt):def add():# nonlocal 关键字用于在内层函数中访问并修改外层函数作用域中的变量nonlocal cntcnt += 1return cntreturn add# 创建一个闭包func_obj = counter(1)print(func_obj())print(func_obj()) 23 可以看到,变量cnt保存在内存中,闭包可以对cnt进行修改
闭包与对象的类比 闭包与对象的功能很相似对象是属性 + + +方法,而闭包可以理解为数据 + + +功能,数据来源于外部函数的局部变量和参数,闭包用于实现功能对象适合实现较复杂的功能,而闭包则更轻量