我叫骆驼 会点儿代码,会点儿读书 这世上的书浩如烟海 我能做的就是尽量整理分享给你起 在上一节Flask项目实战第一弹中我们讲到了路由,先看下面代码回顾一下:fromflaskimportFlaskappFlask(name)app。route(hello)defhello():returnpHelloWorld。。。ifnamemain:app。run(loaddotenvTrue) app。route(hello)就是装饰器。交流群里小伙伴问我,Python里的装饰器该怎么理解,今天我们好好唠唠这个东西。承 说到装饰器,我们不得不谈一个知识点:闭包。我们从代码入手,一点一点来说闭包。 Python有一个好玩的地儿,就是def函数(exterior)内部可以嵌套另一个def函数(interior)。调用exterior时,若遇到interior,仅仅完成对于interior的定义,而不去运行interior。如果exteriorreturninterior,那么我们可以使用interior()去调用内部函数interior函数。var0defexterior():var1definterior():print(var)returninterior()这里返回interior函数调用结果exterior()打印1 从上面代码和结果中可以看到,interior打印的var值并非第一行的var。这说明,exterior中的嵌套变量var覆盖了全局变量var0,然后interior中的本地变量按照引用规则,就引用了var1。 接下来,我们仔细想想下面这句话: interior作用域在函数结束后就立即失效,而exterior嵌套作用域在interior的函数返回后却仍然有效。var0defexterior():var1definterior():print(var)returninterior这里返回interior函数对象interexterior()inter()打印1 看完上面代码,再思考一下刚刚的话。如果还不清楚,看下图: 图解 创建一个闭包必须满足以下几点:必须有一个内嵌函数内嵌函数必须引用外部函数中的变量外部函数的返回值必须是内嵌函数转 现在有了闭包的知识点,我们再聊聊装饰器(decorator)。我要掰开了揉碎了来说说装饰器。 刚刚接触装饰器的同学会对这个概念感到迷茫,然后你在网上(尤其csdn)找例子或者教程,基本千篇一律,或者讲解的点到为止,你在看完之后,或许更迷茫了。 函数是什么 在说装饰器前,我们聊聊Python的函数。众所周知:在Python中,一切皆对象,函数是一等对象。 编程语言理论家把一等对象定义为满足下述条件的程序实体:在运行时创建能赋值给变量或者数据结构中的元素能作为参数传递给函数能作为函数的返回结果 我们看这么一段程序:defdouble(x:int)int:returnx2 这段代码很简单,计算了一个整数的2倍。那么我么用dis模块进行反编译,看看他是怎么运行的。frommytestimportdoublefromdisimportdisdis(double)结果如下 源码行号 指令在函数中的偏移 指令符号 指令参数 实际参数值 2hr0hrLOADFAST 0hrx 2hrLOADCONST 1hr2hr4hrBINARYMULTIRLY 6hrRETURNVALUE 指令符号解释:LOADFAST:一般加载局部变量的值,也就是读取值,用于计算或者函数调用传参等;LOADCONST:加载const变量,比如数值、字符串等等;BINARYMULTIRLY:见名知意,二进制乘法RETURNVALUE:返回值 结合反编译的结果,仔细理解一下代码的运行流程。下面我们看另外一个例子:defdouble(x:int)int:returnx2deftriple(x:int)int:returnx3defcallfunc(func,x:int)int:returnfunc(x)resultcallfunc(triple,2)print(result)dis(callfunc) 源码行号 指令在函数中的偏移 指令符号 指令参数 实际参数值 10hr0hrLOADFAST 0hrfunc 2hrLOADFAST 1hrx 4hrCALLFUNCTION 1hr6hrRETURNVALUE 在运行过程中:出现了CALLFUNCTION。结合第13行代码,仔细体会一下这句话:函数能作为参数传递给另外一个函数。 我们现在看一下闭包的执行流程defcallfunc():defdouble(x:int)int:returnx2returndouble dis(callfunc) 里边出现了一个关键词:MAKEFUNCTION,见名知意,创建函数。此时再回想一等对象所满足的条件。 说了这么多,无非是想告诉大家一个重要的东西,函数就是对象,可以被另一个函数返回,可以被赋值,也可以被调用。 其实到这里,才真是说完闭包这个东西。装饰器和闭包大同小异,下面我们接着来。 装饰器 有这种一种等价语法:defcallfunc(func):return1callfuncdeftriple(x:int)int:returnx3 等价于defcallfunc(func):return1deftriple(x:int)int:returnx3triplecallfunc(triple) 无论上面那种方式,我们输出的tripre这个对象的值都是1print(triple)1 所以,闭包可以写成这种形式呢?其实,装饰器可以理解为闭包的一种,我们可以这样认为:闭包传递的是变量,而装饰器传递的是函数,除此之外没有任何区别。 我们看一个打印时间的装饰器:importtimedeftimeit(func):defwrapper(x):starttime。time()retfunc(x)print(time。time()start)returnretreturnwrappertimeitdefmyfunc(x):time。sleep(x)myfunc(1) timeit装饰器就打印myfunc函数的运行时间。是不是在了解完闭包之后很简单了。 装饰器的作用就是:在不改变原函数的情况下,对已有函数进行额外的功能扩展。 恭喜你,Python技能又进一步。 回到Flask我们看看路由装饰器 Flask中路由的装饰器很简单,我们以route为例,以下是route函数源码(抽离版):importtypingastdefaddurlrule(rule,endpoint,f,param):passdefroute(rule:str,options:t。Any)t。Callable:defdecorator(f:t。Callable)t。Callable:endpointoptions。pop(endpoint,None)addurlrule(rule,endpoint,f,options)returnfreturndecorator route函数就是一个装饰器,内部嗲用addurlrule实现真正的路由添加。再回过头看看装饰器的作用和定义以及使用,是不是明白了许多!加油,慢就快,快就是慢。合 我整理了自学Python的视频,涉及到爬虫、Web、数据分析、机器学习和深度学习等内容,留言转发并后台发送:你好,Python,就可以免费获取啦! 爬虫 我也是从大学一路自学走来的,深知自学的情况下,没有项目是多么的难受。现在免费赠送python项目实战,后台私聊即可获得。 最后,动动手点个赞,您的支持是我创作的最大动力〔比心〕