java中的闭包在jdk1.8之后才出现。
设:函数inner在函数outter里面
def outter():
def inner():
pass
pass
定义
百度百科上的定义
闭包包含自由(未绑定到特定对象)变量,这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)。“闭包” 一词来源于以下两者的结合:要执行的代码块(由于自由变量被包含在代码块中,这些自由变量以及它们引用的对象没有被释放)和为自由变量提供绑定的计算环境(作用域)。
inner就是闭包
自由变量 | outter里的变量,作用域属于 enclosing |
---|
我对闭包的理解
- inner能够访问outter里的变量var_outs
- inner的计算环境指var_outs。通过一些写法,inner将计算结果保存在var_outs(将var_outs更新了)中;inner被再次调用时,可继续使用var_outs。这称为保存inner的当前运行环境
- 外部直接调用inner
- 大概是嵌套函数的妙用
例子
在平面直角坐标系中移动,每次移动都需要在上一次移动结束的位置开始:
通过函数outter中的变量position,函数inner成功保存了每次移动后的位置
# 闭包函数
origin = [0, 0] # 原点
def outter(position=origin):
# position为当前位置
def inner(direction, step):
# direction为移动方向
# step为移动步长
# 保存当前位置
position[0] = position[0] + direction[0] * step
position[1] = position[1] + direction[1] * step
return position
return inner
inn = outter()
print(inn((0, 1), 10)) # 沿y轴走10步
print(inn((1, 0), 10)) # 沿x轴走10步
print(inn((0, 1), 20)) # 沿y轴走20步
函数的__closure__属性
其存储了闭包中关于自由变量的东西
- 是个tuple,存储的是cell对象。一个cell对象,存储一个inner的自由变量
- 只对闭包有效
- __closure__[index].cell_contents访问第index个自由变量的值
def outter(position=origin):
c = 1
b = 2
def inner(direction, step):
nonlocal c, b
b = b
c = c
position[0] = position[0] + direction[0] * step
position[1] = position[1] + direction[1] * step
return position
return inner
inn = outter()
print(inn([1, 0], 10)) # [10, 0]
print(outter.__closure__) # none 也就是说这个属性只作用在闭包上
print(type(inn.__closure__)) # tuple,存储了inner的所有自由变量
print(len(inn.__closure__)) # 3
print(inn.__closure__[0]) # <cell at 0x000002D62D427E88: list object at 0x000002D62B5D6208>
print(inn.__closure__[0].cell_contents) # 2,是b的值,表示自由变量的存储是按字母表顺序
这解释了为什么局部变量脱离函数之后,还可以在函数之外被访问的原因的,因为它存储在了闭包的 cell_contents中了。