Python装饰器详解,实例分析

2018 年印度雅加达亚运会,中国在金牌榜和总奖牌榜都遥遥领先于第二名的日本,我也是一名体育爱好者,平时有比赛也会看。看到中国的国旗在海外飘扬,内心会格外的自豪,中国不再是任人宰割的「东亚病夫」。

今天我结合亚运会带大家理解下 Python 装饰器。

装饰器在我之前发的那篇「用 Python 玩微信,机器人陪你唠嗑」文章大家都见过,没看过的点击这里,我在创建话痨机器人函数和微智能机器人函数前都加了一句代码:

可能当时大家不了解这句代码的含义,其实这就是装饰器。

装饰器是什么?

首先,什么是装饰器呢?Python 装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用 Python 装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。

比如我定义一个函数,孙杨在 200 米自由泳夺冠的函数。

 

这时如果你想加一个功能进去,中国运动员夺冠就会升中国国旗。这时你会怎么做,简单粗暴的方法就是直接修改函数代码。

 

无参数装饰器

如果下次又要加一个功能,你又要改一次代码,如果其他 100 多个夺冠项目都要加这个功能,你一个个复制粘贴,我这举的例子比较简单,如果是复杂的功能,会让人崩溃,代码位置一旦加错,更让人无语了。所以装饰器就可以发挥作用了。刚才说到,使用 Python 装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。这时我可以单独把升国旗这个功能定义成一个装饰器,装饰器的本质也是函数,它的返回值也是一个函数。

这个装饰器就定义好了,它的作用是打印升国旗的项目名称。这样我们就可以用「@装饰器」的方式直接调用装饰器了。

 

调用 Freestyle200m() 函数不仅会运行 Freestyle200m() 函数本身,还会在运行 Freestyle200m() 函数前执行装饰器的功能。

由于 Raising() 是一个装饰器,返回一个函数,所以,原来的 Freestyle200m() 函数仍然存在,只是现在同名的 Freestyle200m 变量指向了新的函数,于是调用 Freestyle200m() 将执行新函数,即在 Raising() 函数中返回的 wrapper() 函数。

装饰器中 wrapper() 函数的参数定义是(*args, **kw),说明接受任意参数的调用。在 wrapper() 函数内,首先打印升国旗项目,再紧接着调用原始函数 Freestyle200m()。

有参数装饰器

我们知道,颁奖的时候会升起获得金牌、银牌、铜牌的选手的国家国旗,演奏的国歌是获取金牌选手的国家的国歌,这时,我们想把奏哪个国家国歌参数化,装饰器本身就得传入一个参数。

 

上面定义的装饰器就定义了一个参数,这个参数是表示国家的,我们调用这个装饰器的时候必须传入这个参数去调用装饰器。

调用之后的效果和下面的表达式是一样的。

它首先执行 Raising(‘中国’),返回的是 decorator 函数,再调用返回的函数,参数是 Freestyle200m 函数,返回值最终是 wrapper 函数。

属性转换

我们知道,函数也是对象,它有 __name__ 等属性,但你去看经过 decorator 装饰之后的函数,它们的 __name__ 已经从原来 Freestyle200 变成了 wrapper。

这是我们需要做个转换,wrapper.__name__ =func.__name__ ,每次都要这样写,很麻烦。你要知道,程序员很会偷懒的,所有就有了functools.wraps。这是 Python 内置的函数,它是专门做这种转换工作的。

这样,一个完整的带参数的装饰器就搞定了,当然,你也可以选择不带参数的装饰器。

 

调用多个装饰器

我们的选手夺冠了,我们很开心,一般会安排接受记者采访。我想加这个功能怎么办?没关系,我们可以同时调用多个装饰器。我们先定义一个记者采访的装饰器。

可以调用这两个装饰器。

 

被多个函数重复调用

装饰器同样可以被其他多个函数调用。
苏炳添,8 月 26 日,在雅加达亚运会田径男子 100 米的决赛中,苏炳添以 9 秒 92 打破亚运会纪录的成绩夺冠。

我们也可以定义苏炳添夺冠的函数来调用装饰器。

前些天,王者荣耀的游戏迷是比较高兴的,因为在「王者荣耀国际版」(AoV)首日表演项目决赛中,中国代表队经过激烈角逐,最终以 2:0 战胜中国台北代表队,获得本届亚运会电竞表演赛的首个冠军。以后,玩王者荣耀的伙伴们可以自豪的说:我是在为国家玩王者荣耀!

装饰器本质上只是个语法糖,使原本苦涩的代码结构变得甜蜜起来。

这样,之前 Python 机器人的项目中创造机器人函数前加的 @robot.register() 就好理解了,register 是用于注册消息配置的装饰器。

好了,今天的文章就讲到这里,希望能帮助大家对装饰器的理解。此文章如果对你有点帮忙的话希望大家能多给点支持,关注、点赞、转发对我都是一种鼓励,有什么问题欢迎在后台联系我,也可以在后台加入技术交流群,群里有大神,可以一起交流学习。

 

文章为pk哥原创,我在我的公众号: Python 知识圈 上会分享更多心得体会,你也可以关注。

***版权申明:本文为 Python知识圈 pyzhishiquan.com 原创,没有Python知识圈书面授权,请勿以任何形式转载,摘编,复制或镜像。***

为您推荐

发表评论

电子邮件地址不会被公开。