Python进阶:闭包和装饰器
一、闭包
1.闭包的前提条件及定义
前提条件: 有嵌套,有引用,有返回
定义: 有内部函数的嵌套,内部函数使用了外部函数的局部变量,外部函数对内部函数进行了返回。
注意: 内部函数依赖外部函数的变量,以此让内部函数正常运行,同时它依赖的外部变量也能得到想要的结果。
2.闭包的语法结构
def outer(out_a):
def inner(in_b):
print(out_a,in_b)
return inner
fn = outer("闭包")
fn("语法结构")
调用outer函数,返回的是inner函数,用一个变量fn接收,因此变量fn的类型为一个可以接收参数的函数。
程序运行结果

3.nonlocal关键字
下面通过一段错误代码来介绍nonlocal关键字:
def outer(num1):
def inner(num2):
num1 += num2
print(num1)
return inner
fn = outer(5)
fn(5)
程序会直接报错,num1是外部函数outer的局部变量,不能在内部函数直接进行修改。
那如何正确的对外部函数的局部变量num1进行修改呢?
答案是使用nonlocal关键字。
def outer(num1):
def inner(num2):
nonlocal num1
num1 += num2
print(num1)
return inner
fn = outer(5)
fn(5)
程序运行结果

nonlocal关键字的作用:在内部函数中,修改外层函数的局部变量;声明变量既不是全局变量 ,也不是自己的局部变量,而是外部函数的局部变量。
在内部函数中使用nonlocal关键字,从而修改外部函数的变量的值
二、装饰器
1.定义
装饰器的本质是函数,也是特殊的闭包,可以理解为在不修改函数原有代码的前提下,为函数添加新的功能。
2.装饰器的写法
1) 闭包写法
把原函数show传给装饰器,得到闭包函数;
用返回的闭包函数覆盖原来的函数名,之后调用get_show函数其实是执行内层函数inner。
# 定义装饰器(使用闭包)
def outer(func):
def inner():
print("原函数添加功能之前")
# 调用原函数get_show
func()
print("原函数添加功能之后")
return inner
# 定义原函数
def get_show():
print("我是原函数")
fn = outer(get_show)
fn()
2) 语法糖
将@装饰器名 写在原函数上方;
再直接调用原函数。
# 定义装饰器(使用闭包)
def outer(func):
def inner():
print("原函数添加功能之前")
# 调用原函数get_show
func()
print("原函数添加功能之后")
return inner
@outer
# 定义原函数
def get_show():
print("我是原函数")
get_show()
两种写法的运行结果相同:
3) 两种写法的总结
闭包写法: 先调用装饰器的外部函数outer,将原函数get_show传入,得到返回值fn,而返回值本质就是装饰器的内部函数inner,最后再调用inner函数。
语法糖写法: 先定义好装饰器函数,用@装饰器名写在原函数上方,最后再调用原函数。
三、global和nonlocal关键字对比
1.作用范围
global:用于修改全局变量(函数外部定义的变量)。
nonlocal:用于修改外层函数的局部变量(嵌套函数中,外层函数的局部变量)。
2.使用场景
global:在任意函数内部,想要修改函数外部的全局变量时使用。
nonlocal:在嵌套内层函数中,想要修改外层函数的局部变量时使用。
global的示例代码:
num = 100 # 全局变量
def test():
global num # 声明使用全局变量
num = 10 # 修改全局变量
test()
print(num) # 输出 10
nonlocal的示例代码:
def outer():
num = 10 # 外部函数局部变量
def inner():
nonlocal num # 声明使用外部变量
num = 20 # 修改外部变量
inner()
print(num) # 输出 20
outer()
四、总结
闭包:满足嵌套 + 引用 + 返回三个条件,内层函数可使用并记住外层函数变量,修改外层变量需用 nonloca关键字l。
装饰器:本质是特殊闭包,在不修改原函数代码的前提下为函数添加新功能,支持闭包手动写法和 @语法糖简化写法。
关键字:global 改全局变量,nonlocal 改外层函数局部变量,二者都用于解决函数内变量修改作用域问题。
更多推荐


所有评论(0)