一、闭包

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 改外层函数局部变量,二者都用于解决函数内变量修改作用域问题。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐