python闭包(Closure),用地址来理解

时间:2022-04-05 22:46:41

代码

#closure
def count():
fs = []
for i in range(1, 4):
print('in count( ): id(i) = ',id(i), ' | i = ', i)
def f():
print('in f(): id(i) = ',id(i), ' | i = ', i)
return i*i
fs.append(f)
return fs

f1, f2, f3 = count()
print(f1)
print(f1())
print(f2)
print(f2())
print(f3)
print(f3())

print("="*20)

def count2():
def f(j):
print('in f( ): id(j) = ', id(j), ' | j = ', j)
def g():
print('in g( ): id(j) = ', id(j), ' | j = ', j)
return j*j
return g
fs = []
for i in range(1, 4):
print('in count2( ): id(i) = ', id(i), ' | i = ', i)
fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
return fs

F1,F2,F3 = count2()
print(F1)
print(F1())
print(F2)
print(F2())
print(F3)
print(F3())

运行结果

in count( ): id(i) =  2012938704  | i =  1
in count( ): id(i) = 2012938736 | i = 2
in count( ): id(i) = 2012938768 | i = 3
<function count.<locals>.f at 0x000000000106E840>
in f(): id(i) = 2012938768 | i = 3
9
<function count.<locals>.f at 0x000000000106E8C8>
in f(): id(i) = 2012938768 | i = 3
9
<function count.<locals>.f at 0x000000000106E950>
in f(): id(i) = 2012938768 | i = 3
9

---
in count2( ): id(i) = 2012938704 | i = 1
in f( ): id(j) = 2012938704 | j = 1
in count2( ): id(i) = 2012938736 | i = 2
in f( ): id(j) = 2012938736 | j = 2
in count2( ): id(i) = 2012938768 | i = 3
in f( ): id(j) = 2012938768 | j = 3
<function count2.<locals>.f.<locals>.g at 0x000000000106EAE8>
in g( ): id(j) = 2012938704 | j = 1
1
<function count2.<locals>.f.<locals>.g at 0x000000000106EB70>
in g( ): id(j) = 2012938736 | j = 2
4
<function count2.<locals>.f.<locals>.g at 0x000000000106EBF8>
in g( ): id(j) = 2012938768 | j = 3
9

Process finished with exit code 0

分析

  • 第一次运行f会跑一次count
  • 在f中用i访问外面一层count的局部变量i的时候是用地址访问的,可以看出i在循环中i地址不断地改变,最后访问的是跑完了count时的最终i的地址。
  • 如果引入一个函数g来存放那个i的地址就可以输出1*1,2*2,3*3了,因为g中j的地址是不会变的