python基础-闭包

时间:2024-04-05 21:06:41
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