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