人人都能看懂的 Python 装饰器入门教程

Posted 梦子mengy7762

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了人人都能看懂的 Python 装饰器入门教程相关的知识,希望对你有一定的参考价值。

大家好,我是萱萱!

之前的文章中提到,很多人认为理解了装饰器的概念和用法后,会觉得自己的 Python 水平有一个明显的提高。

但很多教程在一上来就会给出装饰器的定义以及基本用法,例如你一定会在很多文章中看到例如代码运行时间计时器等相关常用装饰器。

直接从应用入手这样学习当然十分有效,但不是看过就忘就是似懂非懂的状态,因为装饰器从来就不是一个单独的概念,就像数学分析中求积分一样,你可以通过公式快速算出需要求的积分,但是若明白积分是由极限定义的,之后再看积分将会是不一样的视角。

本文我将尝试说清楚为什么需要现装饰器、什么是装饰器、以及如何写一个简单的装饰器,但要彻底理解装饰器还要从函数开始说起,下面是有关函数的四个重要的概念,希望大家可以明白。

01

有关函数的四个重要概念

相信你在大多数文章中,至少也能知道例如「装饰器是装饰函数」,「在不修改函数代码的情况下增加额外功能」等核心概念,但首先要知道为什么函数能够被装饰。

例如在《流畅的Python》一书中,讲到函数的一开始就提出了一个概念,函数是一等对象

正如书中所说,在Python中一个函数既可以作为参数被传递,也能作为另一个函数的返回值,这也是函数可以被装饰的关键,在介绍装饰器之前,下面有必要通过简单的代码对这段话做一个更直观的理解。

1.1 函数中传递函数

函数中传递函数意思就是可以将函数当作变量来使用,我们来看一个简单的示例。

在下面的代码中,func1是一个普通的函数,接受两个参数a,b并返回他们的和。func2不一样的地方在于多接收了一个func参数,这个func变量需要是一个函数

现在让我们来执行

下面func1作为参数执行func2

可以看到,先执行func2,在func2接收到fun1后,再次执行func1并返回。注意这里的func1没有括号,它只不过是和a,b一样的参数被使用,理解这点后我们继续看下一个知识点。

1.2 函数中定义函数

在定义一个函数后,可以继续在函数内部定义新的函数。为了理解这点,我们来看下面简单的示例。

我们先定义了一个函数,并在中定义了,并在的内部调用了

现在执行与看看会发生什么

可以看到,当执行func1时,会自动执行func2,但是如果单独执行func2,则提示未定义,说明func2只能在func1中被调用!

1.3 函数返回函数

最后是一个函数可以将另一个函数作为返回值返回的简单示例,在下面的代码中,我们先定义了一个外部函数(接受一个参数a),之后定义了一个内部函数(接受一个参数b)并返回,最后将作为的返回值返回

需要注意的是,这里返回的func2没有括号,代表返回的是func2的地址!

从上面的运行结果可以看到,当执行后,返回的是的地址,并赋给,之后执行才真正执行了内部函数!

现在我们就解决了上一小节的问题「将内部函数单独拿出来用」!

福利:私信回复【01】可免费获取python入门教程视频
1.4 函数内省

函数内省是相对来说比较好理解的一个概念,在Python中的意思就是我们可以访问函数的部分属性,例如print函数,可以使用dir函数来查看其全部属性

现在可以查看其对应的属性

函数内省了解到这个程度即可,我们会在2.3节再次提到这里的知识!

至此,我已经将接触装饰器之前必须要吃透的知识点介绍完毕,如果你觉得我讲解的不够清晰,可以查看任何其他教程或者书籍弄懂后再继续阅读。

02

初识装饰器

现在终于可以来说说装饰器了,当然绝对不是直接告诉你一个写好的装饰器,而是我们一点一点去写一个简单的装饰器。

2.1 第一个装饰器

在下面的代码中,我们先定义了一个函数,该函数接受函数为参数(如果不理解请查看本文 1.1 节),之后在内部定义了一个名为的内部函数(如果不理解请查看本文 1.2 节),最后返回以作为返回值(如果不理解请查看本文 1.3 节)

这个函数的功能是,在执行被接收函数前后分别打印一段话,所以我们要再定义一个函数来测试效果

这个fun1没有什么好说的,打印一段话。下面需要仔细看了,我们来执行这两段代码

正如我们预料的一样,在执行前后都有一段提示,但是如果每次使用功能都需要先将add传递,之后再调用,来回写好几遍,实在太麻烦了!

因此这完全有更Pythonic的写法,也就是我们常见的装饰器形式,使用语法糖,例如上面的例子和下面的写法等价

用放在需要被装饰函数的上方即可,现在直接调用即可实现装饰器的功能!

相信看到这里,你应该明白装饰器@如何工作的,至少你在未来看到@时需要想到类似等价于一样的作用!

2.2 装饰器传参

上面仅是最简单的装饰器示例,在实际使用时

很自然的想法那就是加上参数呗,改起来也不难

让我们来测试一下

不出意外的报错了,虽然我们给被装饰的函数加上了参数,但是在装饰器的内部函数执行时并没有参数!

因此我们之前的代码可以这么改,使用也是非常常见的用法

现在我们再次使用这个装饰器即可返回我们预测的结果!

03

functools

本文的最后,还需要简单介绍一下在写装饰器时常用的模块。

还记得1.4节的函数内省相关知识吗?我们可以打印一个函数指向的内存地址或者名字等其他属性。

还是上面用到的add函数,我们都知道虽然被装饰了,但是功能上没有任何变化,依旧是计算两个数字的和,但是真的没有任何变化吗?下面让我们来观察一下

可以看到,被装饰后,虽然功能上没有变化,但是它指向的是装饰器所定义的内部函数!这并不是我们希望看到的,比如若不同函数被两个装饰器装饰时则会出现一样的函数名!

幸运的是Python中的库可以轻松解决这个问题,只需要加上一行简单的代码就可以搞定!

可以看到此时函数名等函数属性均保留下来了,事实上通过将原函数中的部分内省属性固定,只传递部分关键参数来实现这个功能,感兴趣的读者可以自行进一步研究。

至此,我想你应该明白为什么需要现装饰器、什么是装饰器、以及如何写一个简单的装饰器,当你再次看到装饰器时,脑海中浮现的概念应该不仅仅是。有关装饰器更高级的用法,以及一些常见、好用的装饰器,我将在装饰器的第二篇文章中进行介绍!

以上是关于人人都能看懂的 Python 装饰器入门教程的主要内容,如果未能解决你的问题,请参考以下文章

小白都能看懂的实战教程 手把手教你Python Web全栈开发 (DAY 5)

小白都能看懂的实战教程 手把手教你Python Web全栈开发 (DAY 4)

小白都能看懂的实战教程 手把手教你Python Web全栈开发 (DAY 6)

收藏 | 人人都能看懂的 LSTM

人人都能看懂的Django REST framework

人人都能看懂的Spring源码解析,Spring如何解决循环依赖