1. 首页
  2. Python

5 分钟全面掌握 Python 装饰器

Python

5 分钟全面掌握 Python 装饰器

5 分钟全面掌握 Python 装饰器
作者:吉星高照, 网易游戏资深开发工程师,主要工作方向为网易游戏 CDN 自动化平台的设计和开发,脑洞比较奇特,喜欢在各种非主流的领域研究制作各种不走寻常路的东西。
Python的装饰器是面试的常客,因为其写法复杂多变,经常忘记什么地方应该写哪种参数,新手学习起来也经常一头雾水,不怕不怕,看了这一篇你对装饰器的各种用法就全明白了。废话不多说,直接进入主题!
入门Python其实很容易,但是我们要去坚持学习,每一天坚持很困难,我相信很多人学了一个星期就放弃了,为什么呢?其实没有好的学习资料给你去学习,你们是很难坚持的,这是小编收集的Python入门学习资料关注,转发,私信小编“01”,即可免费领取!希望对你们有帮助
5 分钟全面掌握 Python 装饰器

5 分钟全面掌握 Python 装饰器
我们先来写一个简单的装饰器,实现将函数运行前后的情况记录下来。
上面只是定义了两个函数,运行后发现竟然有输出:
仔细看看,原来是第一个 print 语句的输出。这说明装饰的函数还没有实际运行的时候,装饰器就运行过了,因为 @dec1 相当于单独的一个语句:
那我们来正式运行一下 f1 吧:
输出如下确实达到了预期的效果:
后面我们还想要给装饰器加上参数呢,先试试用这个方式调用会发生什么情况:
输出了错误:
它说 dec1 需要接受 func 这个参数才行,那我们改改,作为 f2 函数吧:
这下可以了:
可是这个结构和原来有点不同了,而且, after run 要写在哪里呢?很愁人地又改了一版,把它叫做 f2x 吧,对比 dec1 ,又多了一层函数 dec2x_w ,开始有点晕:
运行一下看看,确实是想要的:
后面我们就不加 before/after run 了。
函数 f2x 想要接受参数呢?我们把它叫做 a 吧,比较简单,不就是 _wrap 的参数吗,加上就是了,而且又回到了只有两层函数就可以实现了:
很争气地输出了结果:
下面我们实现一个装饰器,传入一个整数,和函数传入的参数做个加法:
输出 1+2=3 :
从调用的装饰器往里看,注意这三层函数的形参,第一层是装饰器的参数,第二层是函数,第三层是函数的参数,很有规律的排列,先记一下这个规律(要考的)。带两个参数的也是一样的,接着写就可以了:
输出 1+2+3=6 :
如果用不定数量的位置参数,就用 *args 作为形参吧:
顺便输出了一下 f6 的函数名:
咦!怎么肥四!!! f6 怎么是里面那个 _wrap 的名字呢?不怕不怕, functools 提供了一个 wraps 装饰器专治各种不服(在装饰器里面放上另一个装饰器):
这下正常输出 f7 了:
用函数做装饰器局限性太多了,用相同的调用方法,把函数 f7 改成类怎么样?emmm…改造工程有点大,直接看看成品吧:
看看是不是实现了一样的效果:
虽然使用了 __call__ ,但这里的 __init__ 不能省略(因为它需要知道参数个数),否则会出现这个错误:
同时还可以发现, __call__ 只需要两层函数了,去掉了第二层,直接把 _wrap 的函数体往上提了一层!
大概是吃饱了撑着,又想要实现一开始那个不带参数的装饰器了,那就继续敲敲打打一番看看:
赶快运行看看:
咦, f9 的函数名可以直接打印,这下都不用 @wraps 了呢!呃,再仔细看看,这写法好像有些不一样啊:
这里先做个总结,装饰器使用函数名形式(不带括号)和使用函数调用形式(带括号和参数)在实现上是不同的,因为前者是函数本身,而后者是从装饰器函数中返回的函数。这也是 f2 相比 f1 缺少了记录 after run 的原因,因为 dec1 直接调用了 f2 ,而 dec2 先运行得到函数,再把函数返回去调用 f2 。用装饰器类就可以解决这个问题,因为它是对 __call__ 的调用,只需要自己定义一下就可以了。
上面的 f9 要写两个函数,能不能写得和 f1 一样简洁?当然是可以的,使用 __new__ 大法:
这样就避开了函数调用,不用打call了(定义 __call__ 函数),快看它来了:

本文来自投稿,不代表程序员编程网立场,如若转载,请注明出处:http://www.cxybcw.com/28921.html

联系我们

13687733322

在线咨询:点击这里给我发消息

邮件:1877088071@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code