函数嵌套
函数嵌套定义
- 指一个函数里用def语句来创建其它的函数的情况。
- 嵌套内部函数可以访问外部函数的变量和全局变量。
- 嵌套内部函数可以直接修改外部函数或者全局的可变变量。
- 嵌套内部函数不能修改外部函数的不可变变量。如果要修改,在内部函数的开头加上nonlocal 变量名。
- 嵌套内部函数修改全局不可变的变量时,需要在内部函数首行加global。
- Locals()函数返回字典,可以看到当前函数中声明的变量或者函数有哪些。
- Globals()看全局的变量有哪些。里面会有很多系统的东西。
函数嵌套举例
def fn_outer():
print("fn_outer开始")
def fn_inner():
print("fn_inner被调用")
fn_inner()
fn_inner()
print("fn_outer结束")
fn_outer()
result:
fn_outer开始
fn_inner被调用
fn_inner被调用
fn_outer结束
闭包
- 闭包在被返回时,它的所有变量就已经固定,形成了一个封闭的对象,这个对象包含了其引用的所有外部、内部变量和表达式。当然,闭包的参数例外。
- 针对于内嵌函数而言。
- 内嵌函数使用了外部函数的变量。
- 外部函数的返回值是内嵌函数对象(同时会有当时的环境)。
闭包格式
def 外部函数():
...
def 内部函数():
...引用了外部函数的变量
return 内部函数
判断一个函数是否为闭包
- 可以通过函数名.closure 在函数为闭包时,返回一个cell ,如果不是闭包函数则返回None
def fn_outer():
c = "hello"
print("fn_outer被调用")
def fn_inner():
print(c)
print("fn_inner被调用")
return fn_inner
func = fn_outer()
print(func.__closure__)
func()
result:
fn_outer被调用
(<cell at 0x00000249919B0768: str object at 0x00000249918C75A8>,)
hello
fn_inner被调用
def fn_outer():
c = "hello"
print("fn_outer被调用")
def fn_inner():
print("hello")
print("fn_inner被调用")
return fn_inner
func = fn_outer()
print(func.__closure__)
func()
result:
fn_outter被调用
None
hello
fn_inner被调用
闭包的作用
- 记录返回闭包时外部变量的状态。
- 当调用外部函数时,本次返回的闭包中记录了当时调用时外部变量的状态。
- 当下一次调用时,如果外部变量发生变化,则返回闭包时又记录了新的状态。
- 闭包是将函数内部和函数外部连接起来的桥梁。闭包函数不再受函数定义时的层级限制,它可以在其它地方调用。
- 闭包返回时,包裹了外部函数的作用域,该函数无论在何处调用,优先使用自己外层包裹的作用域。
为什么会记录状态
- 保存环境分析
- func1,func2所指向的函数内存空间(parent=f1/f2)中记录了调用时fn_outer的现场。
def fn_outer(a):
print("fn_outer被调用")
def fn_inner():
c = 100
sum = a + c
print("fn_inner被调用")
return sum
return fn_inner
func1 = fn_outer(3)
func2 = fn_outer(10)
sum1 = func1()
sum2 = func2()
print(sum1, sum2)

闭包的优缺点
- 因为保存外部变量的环境,不会及时销毁,占用内存。
- 比较简单,原来需要使用类完成的工作,使用闭包也可以。
闭包应用
def 外部函数:
...
def 内部函数1:
...
def 内部函数2:
...
def 内部函数3:
return (内部函数1, 内部函数2)
return 内部函数3
func = 外部函数()
func1 = func
inner_func1, inner_func2 = func1
inner_func1()
inner_func2()