Python-如何实现闭包函数
1、首先要知道函数的作用域法则LEGB,可以看下面的链接。
一个函数定义后就产生了一个本地域,如果在它内部再定义一个函数,叫嵌套,内部函数也产生了本地域Local。这时相对于内部函数,外部函数的作用域叫嵌套域Enclosed。
根据python的LEGB规则,程序运行找名是由内向外找,所以一个嵌套的函数,就封闭了它内部的函数。在它的作用域外是无法直接调用它内部的函数的。
例如:
def out_1():
a=2
def inner_1():
b=5
return a*b
print(inner_1())
inner_1()
在out_1函数的作用域外是无法调用inner

2、嵌套域内可以自由调用内部函数:
def out_2():
a=2
def inner_2():
b = 5
return a*b
s=inner_2()
return s
print(out_2())
---10

1、外部函数返回内部函数的函数名:
def out_2():
a=2
def inner_2():
b = 5
return a*b
return inner_
inner=out_2()
print(inner)
---<function out_2.<locals>.inner_2 at 0x000001949CDD4730>
输出的是内部函数内存地址。

2、一个函数名加上圆括号就是才能在调用时被执行。所以如果先得到返回结果(函数名),再加括号,就等于间接的在外部调用了内部函数。
入上例,在变量inner后加上圆括号
def out_2():
a=2
def inner_2():
b = 5
return a*b
return inner_
inner=out_2()
print(inner())
---10
将内部函数名的变量inner加上圆括号就实现了一个函数。

3、为了更逼真,可以将变量名写成与内部函数名相同,就会变成和内部函数一样的效果,inner_2()
def out_2():
a=2
def inner_2():
b = 5
return a*b
return inner_2
inner_2=out_2()
print(inner_2())
此时的inner_2()和out_2()同处在全局域Global内。这个inner_2就是个闭包函数。

4、在其他函数调引用闭包的情况。
def out_2():
a=2
def inner_2():
b = 5
return a*b
return inner_2
inner_2=out_2()
print(inner_2())
def fun():
a=100
print(inner_2())
fun()
可以看到,函数fun中的变量a=100并没有影响到inner_2()的值。同样是遵守了LEGB的规则,inner_2引用a首先找到的是它上层的a=2。

5、可以通过一个函数的特殊属性 __closure__来验证。
__closure__是一个内存地址的特殊属性,返回的是个元组,包含内部函数调用的嵌套域的变量地址。可以用cell_contents来查看这些变量值。
例如:
def myOut():
a=20
b=50
e=60
def myInner():
c = 30
return a+b+c
return myInner
myInner=myOut()
a=myInner()
print(myInner.__closure__)
(<cell at 0x00000287C449E8E8: int object at 0x00007FF957AC64F0>,
<cell at 0x00000287C449E948: int object at 0x00007FF957AC68B0>)
print(myInner.__closure__[0].cell_contents)---返回a的值20。
print(myInner.__closure__[1].cell_contents)---返回b的值50.
并没有返回e的值,说明__closure__仅仅返回了被引用的变量的值。

6、总结实现一个闭包函数:
1)函数有嵌套。
2)内部函数引用了嵌套域内的变量,并有返回结果。
3)外部函数返回内部函数的函数名。
4)外部函数被调用时加圆括号,就实现了闭包函数。
