先分解一下楼主提出的问题:
如何理解return一个函数,它与return一个值得用法区别在哪?在wrapper函数中,为什么能返回一个在wrapper函数中没有定义的func函数?
在简单概括一下这两个问题涉及到的Python 知识点 :
接下来源码,我们根据实例,逐一的介绍一下:
函数对象
Python一切皆对象,函数这一语法结构也是一个对象。函数被称为第一类对象,函数可以被当做数据传递。在函数对象中,我们像使用一个普通对象一样使用函数对象,比如更改函数对象的名字,或者将函数对象作为参数进行传递。
函数可以被赋值
执行上述代码,输出如下,请留意代码中的注释信息。
函数可以作为参数传递
执行上述代码,输出如下源码,请留意代码中的注释信息。
函数可以作为返回值
如上示例中,当函数(不带括号)作为返回值时,返回的是函数的内存地址,代码执行顺序及结果,如下:
与上面代码不同的是,接下来我们尝试一下让fun_b返回 return fun(),多了一个括号,代码如下:
当 执行 return fun() 时,实际上是先调用fun_a函数,再将fun_a的返回结果作为fun_c的返回,运行代码,结果如下:
闭包
定义:在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
结合上面例子,一个闭包可以简单理解为调用了一个函数fun_a,这个函数fun_a返回了一个函数fun_b。这个返回的函数fun_b就叫做闭包。在调用函数fun_a的时候传递的参数a、c就是自由变量。
上面例子中,函数 fun_b 与环境变量 a,c 构成闭包。在创建闭包的时候,我们通过fun_a 的参数 a,c明确这两个环境变量的取值,因此确定了函数的最终形式(y = 2b + 10)。我们只需要变换参数a,b就可以获得不同的直线表达函数。由此,我们可以看到,闭包的引入提高代码了代码的可复用性,更加简洁。执行代码,输出结果如下:
修饰器
顾名思义,从字面意思可以理解为,它是用来"装饰"Python的工具,使得代码更具有Python简洁的风格。装饰器本质上是Python函数,能够实现让其他函数在不需要做任何代码变动的前提下增加额外功能。
可以看出,fun_a(fun_b)的执行过程如下:
执行函数fun_a,将fun_b当作参数传进去,fun_b()本身也是对象。执行print (fun()) 代码时,先执行了 fun_b(),然后打印'Run Function B' , 返回 2019-06-11 21:17:27 。print(fun()) 打印了fun_b()的返回结果 2019-06-11 21:17:27 。
使用修饰器进行改造,如下:
执行fun_b相当于 fun_b = fun_a(fun_b) ,只是在定义fun_b时,在其前使用@fun_a 进行修饰。
再引入闭包进行改造,如下:
在fun_a内部的函数retry(),是如何获取fun这个参数来执行的?执行fun_a函数return的是retry这个函数,而retry并没有接受fun这个传参。这就是Python里的闭包的概念,闭包就是指运行时自带上下文(自由变量)的函数,如这里的retry函数,他运行的时候自带了上层函数fun_a传给他的fun这个参数,所以才可以在运行时对fun进行处理和输出。
修饰器实现重试机制
简单的重试机制实现
复杂的重试机制实现
支持重试次数和等待时间,如下:
进一步深入了解修饰器,可以阅读这篇文章: