关于闭包和装饰器我相信这因该是初学者都因该能理解的
关于闭包和装饰器我理解了一周绞尽脑汁,我能把我想到的
给分享出来,我相信这因该是初学者都因该能理解的
import time
def performance(unit):
def perf_decorator(f):
def wrapper(*args, **kw):
t1 = time.time()
r = f(*args, **kw)
t2 = time.time()
t = (t2 - t1) * 1000 if unit=='ms' else (t2 - t1)
print ('call %s() in %f %s' % (f.__name__, t, unit))
return r
return wrapper
return perf_decorator
@performance('ms')
def factorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
print (factorial(10))
#上面语句最后四行代码 等价于 factorial = performance(‘ms’)(factorial)
#运算方式等价于 performance = performance(‘ms’)
factorial = performance(factorial)
#分析上面的语句
#performance(‘ms’) 等价于被调用了 performance == perf_decorator 参数’ms’此时为unit参数作为全局变量
#也就是套了一层函数,去包裹闭包,相当于套娃
#此时闭包运算与原有闭包的两层函数相同,加入的参数unit,进行了一层最外层函数引入全局变量,
#继续解析,这时候最外层的函数返回函数perf_decorator,即下一层的函数,将perf_decorator这个函数赋给了performance,
#此时,最终的意义,只是多了一个最外层函数 performance 代入performance(‘ms’)里面的参数’ms’
#接着函数perf_decorator接受performance带来的参数factorial进行闭包操作引用外部自由变量,
#这里的自由变量是因为最为层的函数,要被回收了本来,但是实际上在内部函数被引用,所以变成了自由变量,绑定了在performance范围内的作用域
#接下来继续运行方式为factorial = perf_decorator(factorial) 这里参数f被实参factorial代替,运行的还是函数perf_decorator(f)
#但实际上是为perf_decorator(factorial)接受一个返回的函数 wrapper,我没搞懂wrapper这里的(args, kw)是接受的什么参数
#难道是factorial(n)里面的n么,我也不确定我再试试展开一下,现在函数应该变成这样了 wrapper = perf_decorator(f)
#或者
def perf_decorator(factorial):
#这里带个函数名进去---------------------------------------------------我是-------------------------------------------------------------------------------------分割线------------------------------------------------------------------------------
def wrapper(args, kw):
#进来以后,因为返回了wrapper这函数名没有其他的运行,
#那我就直接找wrapper
#这里perf_decorator(factorial)带进来一个参数factorial又把这个函数名
#的地址的一个函数factorial(n)给搬家搬过来,具体带进来是不是被引用
#或者被运算之类的这些也不管
#好的继续来,这个参数肯定是有的但是不是n我也不能完全确定,
#但是放什么参数我真的很不确定
#因为这个args, kw可以允许是有无参的说明,-------------------------我是--------------------------------------------------------------------分割线---------------------------------------------------------------------------
t1 = time.time()
#继续执行,ti,-------------------------------------------我是------------------------------------------------------------------------------------------------------分割线-----------------------------------------------
r = factorial(args, kw)
#这里就到了最终的运算,factorial(args, kw),这里的函数引用就是
#引用一开始带来的函数名
#但是指示函数名为什么会被引用,需要理清一个概念就是,这是一个
#地址,关于函数的地址
#要找到这个地址就得找到这个函数名,我在函数名后面加()就算是
#调用,那参数在哪里就是args, kw这里的参数我找到了n,因为一
#开始我带了个函数名进来,我通过地址找到了有个参数n但是我就是
#不晓得是先被带进来,还是运行factorial(n)函数的时候自动运行这
#个参数但是需要有个介质去替换它,如果wrapper(args, kw)这里的
#args, kw我换成空的他就报错了,那我就肯定它是接受n的参数
#的,如果我这里没有factorial(args, kw)这一行代码,或者我没运行
#这个需要装饰的函数,那我运行就是正常了---------------------------------------我是-------------------------------------------------------------------------------------分割线--------------------------------------------------
t2 = time.time()
#这里继续运行一下程序结束时间---------------------------------------------------我是-----------------------------------------------------------------------------------------分割线-------------------------------------------------------------
t = (t2 - t1) * 1000 if unit==‘ms’ else (t2 - t1)
#计算一下运行计算时间---------------------------------------------------我是--------------------------------------------------------------------------------------------------------分割线---------------------------------------------------
print (‘call %s() in %f %s’ % (f.name, t, unit))
#输出指定的语句,这里的unit就是我们最外层的自由变量参数"ms",
#好家伙整这个来了,终于逮到了复制品,在这里被引用了,-------------------------我是---------------------------------------------------------------------------分割线----------------------------------------------------------
return r
#然后返回我们运行的factorial(args, kw)函数,结果为r这个懂吧
#再把这个wrapper返回,一直返回,把输出的结果打包全返回,有哪些,
#1、print (‘call %s() in %f %s’ % (f.name, t, unit))输出语句
#2、返回结果r,实际上计算的就是
#def factorial(n): n = 10 带进去运算
# return reduce(lambda x,y: x*y, range(1, n+1))
#print (factorial(10))
return wrapper
#运算结束,都给我打包按顺序放好,给个地址放在那里,就这个名字wrapper
给老子返回,介于最外层函数,给老子返回
return perf_decorator 这介于performance函数返回一个函数名
然后赋值给了factorial,即一个新的函数名,于原来的哪个不一样了,相当于重新写了一个函数一样。里面多了一个factorial旧函数的功能,
这时候就是一个函数名,我想要用的时候就按照原来的形式,加一个()调用,有参数放参数
factorial(n)就是这么一个玩意,你说装饰器,我就懂了一个概念,就是可以做一个扩充包一样,放一些东西
然而闭包的概念就是双重函数使用,说白了,就参数引用,你要问我什么是闭包,那我只能随手一写,我只能说理解一些函数的引用方式再来吃透一些理论就比较实际一些
下面放上闭包和装饰器的概念
内层函数引用了外层函数的变量(包括它的参数)就构成了闭包
装饰器就是在不改变原函数的调用方式的情况下,在函数的前后添加功能。装饰器完美的展示了开放封闭原则,即对扩展开放,对修改封闭
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构