闭包
介绍
定义
构成条件
代码示例
# 外部函数
def func_out():
num1 = 10
# 内部函数
def func_inner(num2):
result = num1 + num2
print("结果:", result)
# 外部函数返回内部函数
return func_inner
# 获取闭包对象 (new_func就是闭包)
# 这里new_func = func_inner
new_func = func_out()
# 执行闭包
new_func(1)
new_func(10)
运行结果
结果: 11
结果: 20
闭包执行结果说明
闭包的作用
闭包的使用
案例
实现步骤说明
代码实现
示例
# 外部函数:接收姓名参数
def config_name(name):
# 内部函数:保存外部函数的参数,并且完成数据显示的组成
def inner(msg):
print(name + ":" + msg)
# 查看内存地址是否一样
print(id(inner))
# 外部函数返回内部函数
return inner
# 创建张三闭包实例(对象)
zhangsan = config_name("张三")
# 创建李四闭包实例(对象)
lisi = config_name("李四")
# 执行闭包
zhangsan("李四,我们一起开黑吧!")
lisi("我不跟你玩,你太菜了")
zhangsan("我TM")
lisi("你TM")
输出
4369971088
4369971232
张三:李四,我们一起开黑吧!
李四:我不跟你玩,你太菜了
张三:我TM
李四:你TM
修改闭包内使用的外部变量
错误代码
示例
# 外部函数
def func_out():
num1 = 10
# 内部函数
def func_inner():
# 在闭包内修改外部函数的变量
num1 = 20 # 本意上是修改外部函数变量,其实是在闭包内定义了一个局部变量
result = num1 + 10
print("结果:", result)
print("修改前的外部变量:", num1)
func_inner()
print("修改后的外部变量:", num1)
# 外部函数返回内部函数
return func_inner
# 获取闭包对象 (new_func就是闭包)
# 这里new_func = func_inner
new_func = func_out()
# 执行闭包
new_func()
输出
修改前的外部变量: 10
结果: 30
修改后的外部变量: 10
结果: 30
正确代码
示例
# 外部函数
def func_out():
num1 = 10
# 内部函数
def func_inner():
# 在闭包内修改外部函数的变量
# 闭包内修改外部函数变量使用nonlocal关键字
nonlocal num1
num1 = 20
result = num1 + 10
print("结果:", result)
print("修改前的外部变量:", num1)
func_inner()
print("修改后的外部变量:", num1)
# 外部函数返回内部函数
return func_inner
# 获取闭包对象 (new_func就是闭包)
# 这里new_func = func_inner
new_func = func_out()
# 执行闭包
new_func()
输出
修改前的外部变量: 10
结果: 30
修改后的外部变量: 20
结果: 30
装饰器
定义
给已有函数增加额外功能的函数,本质上就是一个闭包函数
功能特点
- 不修改已有函数的源代码
- 不修改已有函数的调用方式
- 给已有函数增加额外的功能
代码
示例
# 定义装饰器
def decorator(func):
def inner():
print("已添加登录验证")
func()
return inner
def comment():
print("发表评论")
# 调用装饰器对已有函数进行装饰:comment=inner
comment = decorator(comment)
comment()
输出结果
已添加登录验证
发表评论
代码说明
装饰器的语法糖
介绍
代码
# 定义装饰器
def decorator(func):
# 装饰器的执行时机:当当前模块加载完成以后,装饰器就会立即执行,对已有函数进行装饰
print("装饰器执行了")
def inner():
print("已添加登录验证")
func()
return inner
# 装饰器的语法糖写法:@装饰器名称
@decorator # comment = decorator(comment)
def comment():
print("发表评论")
# 调用装饰器对已有函数进行装饰:comment=inner
comment()
执行结果
已添加登录验证
发表评论
说明
小结
装饰器的使用
使用场景
1、函数执行时间的统计
代码示例
import time
# 定义装饰器
def decorator(func):
def inner():
# 获取时间:距离1970-1-1-00:00:00的时间差
begin_time = time.time()
func()
end_time = time.time()
result = end_time - begin_time
print("函数执行完成耗时:", result, "秒")
return inner
@decorator # work = decorator(work),work = inner
def work():
for i in range(100):
print(i)
work()
输出
......
98
99
函数执行完成耗时: 0.00038695335388183594 秒
2、输出日志信息
通用的装饰器
带有参数的函数
代码示例
def decorator(func):
# 使用装饰器装饰已有函数的时候,内部函数的类型和要装饰的已有函数的类型保持一致
def inner(a, b):
print("正在执行加法计算...")
func(a, b)
return inner
@decorator
def add_num(num1, num2):
result = num1 + num2
print("计算结果是:", result)
add_num(2, 3)
输出
正在执行加法计算...
计算结果是: 5
带有参数有返回值的函数
代码示例
# 定义装饰器
def decorator(func):
# 使用装饰器装饰已有函数的时候,内部函数的类型和要装饰的已有函数的类型保持一致
def inner(a, b):
print("正在执行加法计算...")
add_num = func(a, b)
return add_num
return inner
@decorator
def add_num(num1, num2):
result = num1 + num2
return result
result = add_num(2, 3)
print("结果为:", result)
输出
正在执行加法计算...
结果为: 5
带有不定长参数和返回值的函数
代码示例
# 定义装饰器
# 该装饰器还可以称为是通用的装饰器
def decorator(func):
# 使用装饰器装饰已有函数的时候,内部函数的类型和要装饰的已有函数的类型保持一致
def inner(*args, **kwargs):
# 在内部函数对已有函数进行装饰
print("正在执行加法计算...")
# *args:把元祖里面的每一个元素按照位置参数的方式进行传参
# **kwargs:把字典里面的每一个键值对按照关键字的方式进行传参
# 这里对元祖和字典进行拆包,仅限于结合不定长参数的函数使用
add_num = func(*args, **kwargs)
return add_num
return inner
# 用装饰器语法糖方式装饰带有参数的函数
@decorator # add_num=decorator(add_num),add_num=inner
def add_num(*args, **kwargs):
result = 0
# args: 元祖类型
# kwargs:字典类型
for value in args:
result += value
for value in kwargs.values():
result += value
return result
result = add_num(2, 2)
print("结果为:", result)
输出
正在执行加法计算...
结果为: 4
多个装饰器的使用
代码示例
def make_div(func):
print("make_div装饰器执行了")
def inner():
result = "<来福>" + func() + "</来福>"
return result
return inner
def make_p(func):
print("make_p装饰器执行了")
def inner():
result = "<p>" + func() + "</p>"
return result
return inner
@make_div
@make_p
def content():
return "python"
result = content()
print(result)
输出
make_p装饰器执行了
make_div装饰器执行了
<来福>
python
</来福>带有参数的装饰器
代码示例
def return_decorator(flag):
# 装饰器只能接收一个参数并且是函数类型
def decorator(func):
def inner(a, b):
if flag == "+":
print("正在努力执行加法计算中...")
if flag == "-":
print("正在努力执行减法计算中...")
func(a, b)
return inner
# 当调用函数的时候可以返回一个装饰器decorator
return decorator
# 加法计算
@return_decorator("+")
def add_num(a, b):
result = a + b
print(result)
# 减法计算
@return_decorator("-")
def sub_num(a, b):
result = a - b
print(result)
add_num(2, 3)
sub_num(1, 4)
输出
正在努力执行加法计算中...
5
正在努力执行减法计算中...
-3
小结
类装饰器
介绍
类装饰器就是通过定义一个类来装饰函数
代码示例
class Mylaifu(object):
def __init__(self, func):
self.__func = func
# 实现__call__方法,让对象变成可调用对象,能够像函数一样使用
def __call__(self, *args, **kwargs):
# 对已有函数进行封装
print("刘来福")
self.__func()
@Mylaifu
def show():
print("梁来福")
show()
输出
刘来福
梁来福