闭包函数与装饰器
本章内容
- 闭包函数
- 闭包函数的实际应用
- 装饰器简介
- 装饰器的简易,进阶,完整版本
- 装饰器模板
- 装饰器语法糖
- 装饰器修复技术
闭包函数
# 闭包函数的两大特征(判断一个函数是不是闭包函数)
1.闭:定义在函数内部的函数
2.包:内部函数使用了外层函数名称空间中的名字
eg:
def uther():
name = 'jason'
def inner():
print(name)
return inner
res = uther()
res()
闭包函数的实际应用
闭包函数是给函数体传参的另外一种方式
1.函数体传参的方式1:形参
def index(username):
print(username)
# 函数体代码需要什么就可以在形参中写什么
index('tony')
2.函数体传参的方式2:闭包
def uther(name):
name = 'jason'
def inner():
print(name)
return inner
res = uther('tony') # 形参name与值tony临时绑定
res()
res1 = uther('jason') # # 形参name与值jason临时绑定
res1()
装饰器简介
装饰器并不是一个新的知识点 而是由前两天所有的函数知识点整合到一起的产物:
名称空间 函数名 闭包函数...
装饰器本质
在不改变被装饰对象原有的'调用方式'和'内部代码' 的情况下给被装饰对象添加新的功能
装饰器的原则
对扩展开放
对修改封闭
eg:
import time
def index():
time.sleep(3)
print('from index')
'''给index函数增加了一个统计执行时间的功能'''
start_time = time.time() # 函数执行之前获取一个时间戳
index()
end_time = time.time() # 函数执行之后获取一个时间戳
print(end_time - start_time) # 两个时间戳的差值就是函数的执行时间
装饰器的简易,进阶,完整版本
简易版
# import time
# def index():
# time.sleep(1)
# print('from index')
'''给index函数增加了一个统计执行时间的功能'''
# start_time = time.time() # 函数执行之前获取一个时间戳
# index()
# end_time = time.time() # 函数执行之后获取一个时间戳
# print(end_time - start_time) # 两个时间戳的差值就是函数的执行时间
'''
1.思考:如果在很多地方都需要调用index 如何统计index执行时间
在很多地方都需要执行统计index函数执行时间的代码
在不同的地方需要执行相同的代码 >>>: 函数
直接通过传参的方式
缺陷1:
代码写死了 无法统计其他函数的执行时间
能否解决?
可以! 将函数名通过形参的形式传入
缺陷2:
封装成函数之后 调用方式改变了 不符合装饰器原则
能否解决?
不可以
'''
# def get_time(func):
# start_time = time.time() # 函数执行之前获取一个时间戳
# func()
# end_time = time.time() # 函数执行之后获取一个时间戳
# print(end_time - start_time) # 两个时间戳的差值就是函数的执行时间
# def home():
# time.sleep(3)
# print('from home')
# get_time(index)
# get_time(home)
"""
第一种直接给函数体传参的方式无法实现装饰器
只能采用第二种给函数体传参的方式试试看了
"""
import time
def index():
time.sleep(1)
print('from index')
def home():
time.sleep(3)
print('from home')
print(home)
def outer(func): # 真正的index被outer局部名称空间存储了
def get_time():
start_time = time.time() # 函数执行之前获取一个时间戳
func() # 调用了真正的index函数
end_time = time.time() # 函数执行之后获取一个时间戳
print(end_time - start_time) # 两个时间戳的差值就是函数的执行时间
return get_time
# res = outer(index) # 左侧的res就是一个普通的变量名
# res()
# a = outer(index) # 左侧的a就是一个普通的变量名
# a()
# b = outer(index) # 左侧的b就是一个普通的变量名
# b()
# index = outer(index)
# index() # 看似调用的index其实调用的是get_time
# print(index) # 全局名称空间中的index指向的是get_time函数体代码
home = outer(home) # 狸猫换太子
进阶版
# 解决的是参数问题
def outer(func_name):
def get_time(*args, **kwargs):
start_time = time.time()
func_name(*args, **kwargs)
end_time = time.time()
print(end_time - start_time)
return get_time
完整版
# 解决的是返回值问题
def outer(func_name):
def get_time(*args, **kwargs):
start_time = time.time()
res = func_name(*args, **kwargs) # 执行真正的index函数
end_time = time.time()
print(end_time - start_time)
# return '不要急躁' # 如何在此处返回真正index函数的返回值
return res
return get_time
装饰器模板
'''编写装饰器其实有一套固定的代码 不需要做任何理解'''
def outer(func_name): # func_name用于接收被装饰的对象(函数)
def inner(*args, **kwargs):
print('执行被装饰函数之前 可以做的额外操作')
res = func_name(*args, **kwargs) # 执行真正的被装饰函数
print('执行被装饰函数之后 可以做的额外操作')
return res # 返回真正函数的返回值
return inner
装饰器语法糖
# 仅仅是让代码编写的更加好看、简洁!!!
# Author:Jason
def outer(func_name):
def inner(*args, **kwargs):
print('执行函数之前的操作')
res = func_name(*args, **kwargs)
# 额外操作
return res
return inner
@outer # 等价于 index = outer(index)
def index(*args, **kwargs):
print('from index')
# index = outer(index) # 总感觉这一行代码有点low!!!
@outer # 等价于 home = outer(home)
def home(*args,**kwargs):
print('from home')
print(index)
print(home)
"""
语法糖内部原理
1.使用的时候最好紧跟在被装饰对象的上方
2.语法糖会自动将下面紧挨着的函数名传给@后面的函数调用
ps:针对之前的周末大作业 只需要单独写一个装饰器 之后使用语法糖装饰即可
"""
装饰器修复技术
# 做到比真的还要真 但是本质其实没有变
# Author:Jason
from functools import wraps
def outer(func_name):
@wraps(func_name)
def inner(*args, **kwargs):
print('执行被装饰对象之前可以做的操作')
res = func_name(*args, **kwargs)
return res
return inner
@outer
def index():
print('from index')
@outer
def home():
'''这是home函数的注释'''
print('from home')
# help(home) # help可以查看指定函数的注释信息
# help(len)
# index() # 目前的以假乱真 有瑕疵
# print(index)
# help(home)
# help(index)
# print(home)
# print(index)
home()
index()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)