【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步入调试,则会跳转至此行代码处,如下所示:

(未完待续)

浙公网安备 33010602011771号