Python基础篇---闭包函数和装饰器
本章内容
• 闭包函数
• 装饰器简介
• 装饰器版本
• 装饰器模板
• 装饰器语法糖
• 装饰器修复技术
闭包函数
闭包函数的概念
闭:定义在函数内部的函数
包:内部函数使用了外层函数名称空间中的名字
def outer(): x = 999 def inner(): # inner函数在outer里面,符合闭的特征 print('from outer>>>inner',x) # 变量名x 是从外层函数outer获取值 return inner x = 666 res = outer() res()
def outer(username): # username = 'jason' def index(): print(username) # 永远使用的都是jason return index res = outer('kevin') # 形参username与值kevin临时绑定 >>>:outer局部名称空间中 res() # 输出 kevin res1 = outer('jason') # 形参username与值kevin临时绑定 >>>:outer局部名称空间中 res1() # 输出 jason
装饰器简介
装饰器并不是一个新的知识点 而是名称空间,函数名和闭包函数的知识点整合起来的产物。
装饰器的本质是在不改变装饰对象原有的'调用方式'和'内部代码'的情况下给被装饰对象添加新的功能。
装饰器的原则是对扩展开放,对修改封闭。
装饰器版本
我们知道了什么是装饰器,就让我们来看一下装饰器是如何使用的。
简易版本的装饰器
'''给index函数增加了一个统计执行时间的功能'''
import time def index(): time.sleep(1) print('index函数') def home(): time.sleep(2) print('home函数') def outer(func): # 真正的index被outer局部名称空间存储了 def inner(): start_time = time.time() func() # 调用了真正的index函数和home函数 end_time = time.time() print(end_time - start_time) return inner # 狸猫换太子 index = outer(index) index() # 看似调用的index其实调用的是inner home = outer(home) home() # 看似调用的home其实调用的是inner
这个时候我们调用写的是函数本身的函数名加括号,符合装饰器的原则并且能够实现统计执行时间的功能,我们的简单装饰器就写好了。
如果我们的函数本身带有参数,那我们写装饰器的时候还要考虑参数的问题,
但我们之前学过可变长形参,所以只要在闭包函数上增加可变长形参就可以实现不考虑参数的问题。
import time def index(a): time.sleep(1) print('index函数',a) def outer(func): def inner(*args,**kwargs): # 添加可变长形参 start_time = time.time() func(*args,**kwargs) # 调用了真正的index函数 传参 end_time = time.time() print(end_time - start_time) return inner index = outer(index) index(111)
简单,只要在函数里先添加一个变量名接收被装饰函数的返回值,再用return换行即可。
import time def index(a): time.sleep(1) print('index函数') return a def outer(func): def inner(*args,**kwargs): start_time = time.time() res = func(*args,**kwargs) # 用res接收index的返回值 end_time = time.time() print(end_time - start_time) return res return inner index = outer(index) print(index(111))
装饰器模板
装饰器确实很难理解,没有搞懂也很正常,这时候就要请出我们的大力助手--装饰器万能模板了,以后我们写装饰器就可以通过模板去写。
'''编写装饰器其实有一套固定的代码 不需要做任何理解''' def outer(func_name): # func_name用于接收被装饰的对象(函数) def inner(*args, **kwargs): print('执行被装饰函数之前 可以做的额外操作') res = func_name(*args, **kwargs) # 执行真正的被装饰函数 print('执行被装饰函数之后 可以做的额外操作') return res # 返回真正函数的返回值 return inner
以上的装饰器解决了函数的参数和返回值的问题,为了更简洁而优雅地使用装饰器,Python提供了专门的装饰器语法来取代index=outer(index)的形式。
只要在被装饰对象的正上方单独一行添加@outer,就会把它正下方的函数名当做实参传入,然后将返回的结果重新赋值给原函数名。
我们称这个装饰器语法为语法糖,因为很简单很编辑,所以很甜!
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.语法糖会自动将下面紧挨着的函数名传给@后面的函数调用
装饰器的修复技术
当我们装饰好一个函数后,就按照上方语法糖里的代码为例子,如果查看index的函数名其实是inner,
那我们想要index保留原有的函数名,就需要用到装饰器的修复技术,我们采用functools模块下提供一个装饰器wraps来实现。
from functools import wraps # 导入模块 def outer(func_name): @wraps(func_name) # 使用wraps修复 def inner(*args, **kwargs): res = func_name(*args, **kwargs) return res return inner @outer def index(): print('这里是index函数') print(index) # <function index at 0x000001F50D59C2F0>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人