18-嵌套函数、闭包
嵌套函数
- 在函数中定义另一个函数称为嵌套函数。
- 嵌套函数可以访问包围范围内的变量。
def print_msg(msg):
def printer():
print(msg)
printer()
print_msg("Hello")
执行结果:
Hello
嵌套函数的调用
def func1():
print('func1')
def func2():
print('func2')
func1()
执行结果:
func1
为什么函数func2没有被执行?
任意一个函数定义完成之后,如果没有人通过名字调用它,就永远不会执行,如果需要执行可以按照如下方式进行调用:
def func1():
print('func1')
def func2():
print('func2')
func2()
func1()
执行结果:
func1
func2
nonlocal 关键字
内层函数改变外层函数变量用nonlocal, nonlocal不能定义新的外层函数变量,只能改变已有的外层函数变量,同时nonlocal不能改变全局变量。
不加nolocal关键字
def outer():
a = 1
def inner():
a += 1
print("Inner", a)
inner()
print("Outer", a)
outer()
执行结果:
---------------------------------------------------------------------------
UnboundLocalError Traceback (most recent call last)
<ipython-input-9-7b758191e4f5> in <module>()
9 print("Outer", a)
10
---> 11 outer()
<ipython-input-9-7b758191e4f5> in outer()
6 print("Inner", a)
7
----> 8 inner()
9 print("Outer", a)
10
<ipython-input-9-7b758191e4f5> in inner()
3
4 def inner():
----> 5 a += 1
6 print("Inner", a)
7
UnboundLocalError: local variable 'a' referenced before assignment
添加nolocal关键字
def outer():
a = 1
def inner():
nonlocal a
a += 1
print("Inner", a)
inner()
print("Outer", a)
outer()
执行结果:
Inner 2
Outer 2
闭包
闭包也称词法闭包,如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure),这里说的作用域就是nonlocal。
通俗来讲,闭包就是把一个函数(方法)作为一个变量来使用。
在python中创建闭包必须满足的标准将在以下几点:
- 必须有一个嵌套函数(函数内部的函数)。
- 嵌套函数必须引用封闭函数中定义的值。
- 闭包函数必须返回嵌套函数。
利用闭包实现一个计数器:
def counter():
i = 0
def nested():
nonlocal i
i += 1
return i
return nested
c = counter()
print(c(),c(),c(),end=" ")
返回的函数并没有立刻执行,而是直到调用了c()才执行。
返回的函数中不要引用循环变量:
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
print(f1())
print(f2())
print(f3())
执行结果:
9
9
9
全部都是9!原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9。
如果一定要使用循环变量,解决方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:
def count():
def f(j):
def g():
return j*j
return g
fs = []
for i in range(1, 4):
fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
return fs
f1, f2, f3 = count()
print(f1())
print(f2())
print(f3())
执行结果:
1
4
9