【python】:闭包和装饰器

一、闭包的标准定义

闭包函数中,return返回的函数多了一对括号(),也就是说:func_out 函数最后返回的是 func_inner()(带括号),这表示返回的是内部函数执行后的结果(也就是 None),而不是返回内部函数本身。所以后续调用 new_func() 时会报错,因为 new_func 实际是 None,不能被调用。

正确代码如下:

去掉括号后,所有报错都消失了,并且可以正确运行,如下:

这样就形成了一个基本且正确的闭包形式,如下:

#闭包的作用:可以保存外部函数的变量

#闭包的形成条件
#1、函数嵌套
#2、内部函数使用了外部函数的变量或者参数
#3、外部函数返回内部函数,这个使用了外部函数变量的内部函数称为闭包

#1、函数嵌套
def func_out():
    num1 = 10

    def func_inner():
        #2、内部函数使用了外部函数的变量
        result = num1 + 10
        print("结果:", result)
    #3、 外部函数要返回内部函数,这个使用了外部函数变量的内部函数称为闭包
    return func_inner


#获取闭包对象
#这个new_func就是闭包
#这里的new_func = func_inner
new_func = func_out()
new_func()

更改一下,给闭包内部的函数增加参数,如下:

#闭包的作用:可以保存外部函数的变量

#闭包的形成条件
#1、函数嵌套
#2、内部函数使用了外部函数的变量或者参数
#3、外部函数返回内部函数,这个使用了外部函数变量的内部函数称为闭包

#1、函数嵌套
def func_out():
    num1 = 10

    def func_inner(num2):
        #2、内部函数使用了外部函数的变量
        result = num1 + num2
        print("结果:", result)
    #3、 外部函数要返回内部函数,这个使用了外部函数变量的内部函数称为闭包
    return func_inner


#获取闭包对象
#这个new_func就是闭包
#这里的new_func = func_inner
new_func = func_out()
new_func(1)

运行结果如下:

总结:

#闭包的形成条件
#1、函数嵌套
#2、内部函数使用了外部函数的变量或者参数
#3、外部函数返回内部函数,这个使用了外部函数变量的内部函数称为闭包

二、闭包的使用

# 外部函数接收姓名参数
def config_name(name):
    # 内部函数保存外部函数的参数,并且完成数据显示的组成
    def inner(msg):
        print(name + ":" + msg)

    print(id(inner))
    return inner


#创建tom闭包实例
tom = config_name("tom")
#创建jerry闭包实例
jeff = config_name("jeff")

运行结果如下:

可见,tom和jeff这两个实例的内存地址是不一样的;


下面用闭包实现对话,如下:

# 外部函数接收姓名参数
def config_name(name):
    # 内部函数保存外部函数的参数,并且完成数据显示的组成
    def inner(msg):
        print(name + ":" + msg)

    print(id(inner))
    return inner


#创建tom闭包实例
tom = config_name("tom")
#创建jerry闭包实例
jeff = config_name("jeff")
# 如果执行tom闭包,因为已经保存了name参数,那么以后在输入的时候都是tom说的话:XXXXXX
tom('我是tom,大家一起玩吧!')
jeff('打死也不去!')
tom('我不吃人的!')
jeff('谁相信呢!')

运行 如下:


三、修改闭包内使用的外部变量

# 1、函数财大
def func_out():
    num1 = 10

    def func_inner():
        # 在闭包内修改外部函数的变量
        num1 = 20   #本意是修改外部函数的变量,本质是在闭包内定义了局部变量
        # 2、内部函数使用外部函数的变量
        result = num1 + 10
        print(result)

    print('修改前的外部变量:', num1)
    func_inner()
    print('修改后的外部变量:', num1)
    # 3、返回内部函数
    return func_inner


# 创建闭包对象
new_func = func_out()
new_func()

运行结果如下:


下面使用nonlocal关键字修改闭包内的外部函数的变量,如下:

# 1、函数财大
def func_out():
    num1 = 10

    def func_inner():
        # 在闭包内修改外部函数的变量
        # num1 = 20   #本意是修改外部函数的变量,本质是在闭包内定义了局部变量
        # 在闭包内修改外部函数的变量需要使用nonlocal关键字
        nonlocal num1
        num1 = 20
        
        # 2、内部函数使用外部函数的变量
        result = num1 + 10
        print(result)

    print('修改前的外部变量:', num1)
    func_inner()
    print('修改后的外部变量:', num1)
    # 3、返回内部函数
    return func_inner


# 创建闭包对象
new_func = func_out()
new_func()

运行结果如下:


四、装饰器

1、装饰器的定义

就是给已有函数增加额外功能的函数,它本质上还是一个闭包函数;

装饰器的功能特点:

1、不修改已有函数的原代码

2、不修改已有函数的调用方式

3、给已有函数增加额外的功能

# 装饰器的目的是已有函数进行额外功能的扩展

# 定义装饰器
def decorator(func):    # 如果闭包函数的参数有且只有一个,并且是函数类型,那么这个闭包函数就称为装饰器
    def inner():
        print('已添加登陆验证!')
        func()
    return inner


def comment():
    print('发表评论')


# 调用装饰器对已有函数进行装饰
comment = decorator(comment)
comment()

通过调试可见,comment=inner,如下所示:

运行结果如下:


2、装饰器语法糖的写法

# 装饰器的目的是已有函数进行额外功能的扩展

# 定义装饰器
def decorator(func):    # 如果闭包函数的参数有且只有一个,并且是函数类型,那么这个闭包函数就称为装饰器
    def inner():
        print('已添加登陆验证!')
        func()
    return inner


# 装饰器语法糖写法:@装饰器名称,装饰器的语法糖就是在装饰函数后,写法更加简单
@decorator      # 等价于comment = decorator(comment),就是说装饰器语法糖对此代码进行了封装。
def comment():  # 此处的comment = inner
    print('发表评论')


# 调用装饰器对已有函数进行装饰
# comment = decorator(comment)

# 调用方式不变
comment()

对代码进行调试,如下:

当调试指向@decorator的时候,可以看到@decorato指向的内存地址是:<function decorator at 0x00000205946CB420>,也就是说指向的是def decorator(func):处,如下:

再继续向下调试,调试到代码return inner处,可以看到如下:

此处相当于将comment()函数以参数的形式传递到decorator(func)中,那么func = comment

再继续运行代码,运行到最后一行comment()处,可见如下:

这时,在

print('已添加登陆验证!')

处添加断点,继续F7步入调试,则会跳转至此行代码处,如下所示:

(未完待续)

posted @ 2026-01-11 20:50  chenlight  阅读(7)  评论(0)    收藏  举报  来源