35.闭包

李光朱课程 2024-03-26 04:34:32

函数嵌套

import builtinsbuiltins.b=1 #b为内置变量g=0 #g为全局变量 #定义outer函数(外部函数)def outer(a,c=2): #a、c为自由变量 e=3 #e为自由变量 #定义内部函数 def inner(d,f=4): #d、f为局部变量 print(d,f,a,c,e,g,b) #调用内部函数 inner(6)#调用外部函数outer(5)

运行结果:

6 4 5 2 3 0 1函数引用# 定义函数可以理解为:# 定义了一个全局变量,其变量名字是函数的名字,即test# 这个test变量指向了一个代码块,这个代码块是函数# 其实就是说test保存了一个代码块的地址,即引用def test(): print("--- in test func----")test() # 这是调用函数ret = test # 用另外一个变量 复制了 test这个引用,导致ret变量也指向那个 函数代码块# 下面输出的2个地址信息是相同的print(id(ret))print(id(test))# 通过引用调用函数ret()

运行结果:

--- in test func----140212571149040140212571149040--- in test func----闭包的概念

闭包(closure) 定义非常抽象,很难看懂

下面尝试从概念上去理解一下闭包:

在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。 —— 维基百科https://zh.wikipedia.org/wiki/闭包_(计算机科学)

用比较容易懂的人话说:就是当某个函数被当成对象返回时,夹带了外部变量,就形成了一个闭包。可以这样理解,闭包就是能够读取其他函数内部变量的函数

看如下案例,便于理解什么是闭包:

def make_printer(msg): # 可以认为是 外部函数 def printer(): # 可以认为是 内部函数 print(msg) return printer # 返回的内部函数的引用printer = make_printer('Good!')printer()

运行结果:

Good闭包案例

代码示例:

def test(number): def test_in(number_in): print("in test_in 函数, number_in is %d" % number_in) return number + number_in return test_in# 给test函数赋值,这个20就是给参数numberret = test(20)# 注意这里的100其实给参数number_inprint(ret(100))# 注意这里的200其实给参数number_inprint(ret(200))

运行结果:

in test_in 函数, number_in is 100120in test_in 函数, number_in is 200220使用闭包需要注意的问题

由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。因此可以手动解除对匿名函数的引用,以便释放内存。

使用闭包修改外部函数中的变量def counter(start=0): def add_one(): nonlocal start # nonlocal 关键字用于在嵌套函数内部使用变量,其中变量不应属于内部函数。 start += 1 return start return add_onec1 = counter(5) # 创建一个闭包print(c1())print(c1())c2 = counter(50) # 创建另外一个闭包print(c2())print(c2())print(c1())print(c1())print(c2())print(c2())

运行结果:

675152895354多个闭包

如上面的代码中,调用了2次counter,也就意味着创建了2个闭包,并且每个闭包之间没有任何关系。

大家是否有种感觉,好像闭包与对象有些类似。确实是这样的,对象其实可通俗的理解为数据(属性) + 功能(方法),而闭包也可以理解为数据 + 功能,只不过此时数据是外部函数中的那些局部变量或者形参,而功能则是内部函数。对象适合完成较为复杂的功能,而闭包则更轻量

闭包总结闭包定义是在函数内再嵌套函数闭包是可以访问另一个函数局部作用域中变量的函数闭包可以读取另外一个函数内部的变量闭包可以让参数和变量不会被垃圾回收机制回收,始终保持在内存中(而普通的函数调用结束后 会被Python解释器自动释放局部变量)

0 阅读:0

李光朱课程

简介:感谢大家的关注