前言
上一章我们讲了函数的本质,今天我们谈谈python的装饰器,这是一个现实开发中很常用的东西,快快学起来吧~
需要函数本质作为理论基础,忘了的童鞋翻一翻:Python进阶之函数的那些事
装饰器基础知识
装饰器定义:装饰器是可调用的对象,其参数是另一个函数(被装饰的函数)。 装饰器会处理被装饰的函数,然后把它返回,或者将其替换成另一个函数或可调用对象。
但是装饰器是有限制的:装饰器不能修改被装饰函数的源代码逻辑、装饰器不能修改被装饰函数的调用方式。
接下来,我们先看看学习装饰器需要的功能储备吧:
- 函数即变量(之前讲过了,这点略过)
- 高阶函数
- 嵌套函数 + 闭包
高阶函数
当函数可以满足以下这两个条件之一,就可以称为高阶函数。
①把一个函数名当作实参传给另一个函数
- 如上图,就是高阶函数的一种,他将hello函数传给了show_time,完成了
函数运行计时功能
- 它实现了不修改另一个函数源代码的前提下为其添加功能,但是改变了函数的调用方式
②函数的返回值是另一个函数
- 这也是高级函数的一种,它实现了不修改函数的调用方式,为其函数添加新功能这一特点。
- 但却有局限性,添加的功能全部在运行功能函数的上方,不灵活。
这两个高级函数都实现了装饰器一部分的功能,我们需要其他知识点来完善它。
嵌套函数
嵌套函数的定义是,在一个函数内又有用def 声明的另一个函数。
嵌套函数是这样的:
1 | def foo(): |
闭包
函数的内部引用了函数外部的变量,这就是闭包。
假如有个名为 avg 的函数,它的作用是计算不断增加的系列值的均值;例如,整个历史中某个商品的平均收盘价。每天都会增加新价格,因此平均值要考虑至目前为止所有的价格。
我们使用高阶函数进行编写这个函数的功能:
可以看到,我们实现了功能,但是这里面隐藏了个细节——闭包!
运行此函数时,返回嵌套函数的引用,那么 agv=make_averager()就得到了一个对象(averager的内存地址),问题来了,为什么函数内部还可以调用已经运行完毕的外部函数体中的series列表?不应该是函数运行之后,该函数体就跟着销毁吗?
原因是这样的:在 averager 函数中,series 是自由变量(free variable)。自由变量指未在本地作用域中绑定的变量。
闭包它会保留定义函数时存在的自由变量的绑定,这样调用函数时,虽然定义作用域不可用了,但是仍能使用那些绑定。
一个装饰器
1 | import time |
运行结果如下:
- run是功能函数的函数名,表示下面的函数将作为实参传入foo。
- @后面跟的是添加新功能的函数(也就是装饰器),这个就类似于我们上面高阶函数第二点写过的 run = foo(run),它使得我们不更改函数调用方式的前提下,添加新功能。
- 这一次,我们既没有修改被装饰函数的源代码逻辑、也没有修改被装饰函数的调用方式。一个简单的装饰器就被我们做出来啦!
写在最后
今天讲解了装饰器的内部实现过程,那么这篇文章就到这里了,期待下回与你们相遇。
see you~