python基础-闭包
def bibao(): li = [] n = [1] def inner(): li.append(n[0]) n[0] +=1 print(li) return inner b = bibao() b() b() 结果分别为[1]和[1,2]
1.简述
内部函数被当做对象返回时,夹带了这个内部函数之外的自由变量
闭包:带着当前变量环境的函数
b是inner函数,具有当前变量的值,li是一个空列表,n=[1]
b(),当b被调用时,li.append(1),n=[2],li=[1],这些变量都被存储在了__closure__中
b.__closure__返回值是一个列表,包含自由变量li和n的值
2.典型错误
def wrapper(): n = 1 def inner(): n += 1 print(n) return inner w = wrapper() w() w()
运行时会抛出异常
UnboundLocalError: local variable 'n' referenced before assignment
原因是n=n+1时将n变为局部变量,不再是inner函数外的自由变量,可以通过下面的例子证明
1.不在inner内部对n进行赋值时,n仍然为外部变量
def wrapper(): n = 1 def inner(): print(n) return inner w = wrapper() w() print(w.__closure__)
打印结果为:(<cell at 0x101dc92b8: int object at 0x100983c20>,)
证明此时是有外部变量的
2.在inner内部对n进行赋值时,n变为局部变量
def wrapper(): n = 1 def inner(): n = 1 print(n) return inner w = wrapper() w() print(w.__closure__)
打印结果为:None
证明此时n变为了局部变量
3.针对2中的错误,解决办法
使用 nonlocal将n的属性变为不是局部变量
def wrapper(): n = 1 def inner(): nonlocal n n = n + 1 print(n) return inner w = wrapper() w() print(w.__closure__)
(<cell at 0x101dc92b8: int object at 0x100983c40>,)
打印结果中又有自由变量了
nonlocal表示n不是局部变量,不改变它的属性
4.注意
4.1 具体参考python官网:https://www.python.org/dev/peps/pep-3104/
4.2 如果在自由变量中未声明,直接在函数内部使用的nonlocal,会报错
def wrapper(): n = 1 def inner(): nonlocal n n = n + 1 print(n) m = 1 nonlocal m return inner w = wrapper() w() print(w.__closure__)
如上代码会报错
SyntaxError: name 'm' is assigned to before nonlocal declaration
m必须先是声明为自由变量
5.装饰器与@
pass