深入浅出Python装饰器
1.前言
装饰器是Python的特有的语法,刚接触装饰器的同学可能会觉得装饰器很难理解,装饰器的功能也可以不用装饰器实现,但是装饰器无疑是提高你Python代码质量的利器(尤其是使用在一些具有重复功能的场景),是Python程序员的必备技能.下面我将由浅入深的讲解装饰器语法.在学习装饰器前请记住一点.
装饰器的本质就是函数
2.Python函数
既然装饰器是函数,那我们就先从函数说起
Python中的函数很简单,比如:
def add(a, b):
return a+b
这就是一个标准的函数,有形参有返回值,知道这么多就够了!
3.在函数里面定义函数
Python的语法很自由,这使我们可以在函数里面定义一个函数.举个例子:
def func():
def inFunc():
print("---我在里面---")
当然这么写那么里面的函数就永远不会被执行.如何让里面的函数执行呢?有两种方法,我相信聪明的你们都已经猜到了!
1.在函数里面调用函数里面定义的函数,请看例子:
def func():
def inFunc():
print("---我在里面---")
inFunc()
这样子当我们在调用func()函数时,就实现了两步:
- 定义了一个函数inFunc()
- 调用了刚刚定义的函数
这样就可以执行内部函数了
2.第二种方法就是将内部函数返回给外部变量,用外部变量调用
4.返回一个函数
def func():
def inFunc():
print("---我在里面---")
return inFunc
f = func()
if __name__ == '__main__':
f()
注意返回时不要在函数名后面加()
,因为加上()
代表执行这个函数的意思.
上面的代码运行到f = func()
时因为func
后面加了()
就回去执行func
函数,func
函数先会定义一个inFunc
函数,然后没有执行就把刚定义的函数返回,变量f
接收了func
返回的函数,f()
就执行了刚刚接收的函数,即inFunc
函数
5.函数作为参数
既然函数里面可以定义函数,函数又可以返回函数,那么函数的参数也可以是函数吗?答案是肯定的,看个例子:
def func():
print("---我是函数func---")
def otherFunc(f):
f()
if __name__ == '__main__':
otherFunc(func)
这个例子很简单,你们可以自己理一下,这里就不在解释了,这个例子只是为了说明Python中函数的参数是可以为函数的.
6.把上面的组合起来
其实我们认为高大上的装饰器就是把我上面所说的拼在一个函数里就是装饰器了.
如下所示:
def myDecorator(func): # 函数参数
def inMyDecorator(): # 定义内部函数
func() # 调用参数传进来的函数
print("---我就加了一丢丢新功能---")
return inMyDecorator # 返回内部定义的函数
那我们要怎么调用它呢,按照之前的逻辑先要定义一个函数作为上面那个函数的参数吧(其实这就是被装饰的函数)这里定义一个函数myFunc
如下
def myFunc():
print("---这是我的函数---")
然后呢?总要用一个变量来接收上面那个函数吧,接收完后总要调用吧.那么总的代码如下:
def myDecorator(func): # 函数参数
def inMyDecorator(): # 定义内部函数
func() # 调用参数传进来的函数
print("---我就加了一丢丢新功能---")
return inMyDecorator # 返回内部函数
def myFunc():
print("---这是我的函数---")
f = myDecorator(myFunc)
if __name__ == '__main__':
f()
输出:
---这是我的函数---
---我就加了一丢丢新功能---
看!这是不是有点像装饰器的样子了呢!但总感觉有什么不像(装饰器可没有变量f
),那好吧,把f
换成myFunc
就好了吧(虽然他是之前函数名,但我们是可以改变他指向的内存空间的,一句话:用过的名字还是可以再被利用的)
再看:
def myDecorator(func): # 函数参数
def inMyDecorator(): # 定义内部函数
func() # 调用参数传进来的函数
print("---我就加了一丢丢新功能---")
return inMyDecorator # 返回内部函数
def myFunc():
print("---这是我的函数---")
myFunc = myDecorator(myFunc)
if __name__ == '__main__':
myFunc()
输出:
---这是我的函数---
---我就加了一丢丢新功能---
这下看着舒服多了.
解释一下上面代码的执行过程:
- 定义了函数
myDecorator
(实际上就是装饰器) - 定义了函数
myFunc
(实际上就是被装饰的函数) - 执行到
myFunc = myDecorator(myFunc)
- 这里转去执行
myDecorator
函数,并把myFunc
作为参数传给myDecorator
函数 myDecorator
函数的形参func
接收了实参myFunc
函数- 在
myDecorator
函数里面定义了一个inMyDecorator
函数,没有执行这个函数而是把这个函数给返回了 - 变量
myFunc
接收了myDecorator
函数的返回值即inMyDecorator
函数
- 这里转去执行
- 调用
myFunc
函数,注意这里的myFunc
函数已经不是最初定义的那个函数了,而是inMyDecorator
函数- 执行
myFunc
函数相当于执行inMyDecorator
函数 - 在
inMyDecorator
函数内先调用了func
,这个func
就是第2步定义的函数- 转去执行第2步定义的函数,即打印
"---这是我的函数---"
- 转去执行第2步定义的函数,即打印
- 执行到
print("---我就加了一丢丢新功能---")
这句打印"---我就加了一丢丢新功能---"
- 执行
- 结束
7.使用@
符号
其实Python中为了我们的省力把很多的步骤都用一个@
符号代替掉了
看一个装饰器的官方写法(使用@
符号):
def myDecorator(func): # 函数参数
def inMyDecorator(): # 定义内部函数
func() # 调用参数传进来的函数
print("---我就加了一丢丢新功能---")
return inMyDecorator # 返回内部函数
@myDecorator
def myFunc():
print("---这是我的函数---")
if __name__ == '__main__':
myFunc()
其实这段代码的功能和之前的写法是一模一样的.
@myDecorator
def myFunc():
print("---这是我的函数---")
等价于
def myFunc():
print("---这是我的函数---")
myFunc = myDecorator(myFunc)
8.被装饰的函数带参数
之前写的函数例子都是不带参数的,但是实际上带参数的函数更为常见,那如何向函数传参数呢?仔细想想,myFunc
函数在被装饰后就是inMyDecorator
函数.那么只要想办法步参数传给inMyDecorator
函数不就行了嘛
代码稍作修改(就改了两处):
def myDecorator(func): # 函数参数
def inMyDecorator(*args, **kwargs): # 定义内部函数
func(*args, **kwargs) # 调用参数传进来的函数
print("---我就加了一丢丢新功能---")
return inMyDecorator # 返回内部函数
def myFunc(a):
print("---这是我的函数参数:{}---".format(a))
myFunc = myDecorator(myFunc)
if __name__ == '__main__':
myFunc("kainhuck")
输出:
---这是我的函数参数:kainhuck---
---我就加了一丢丢新功能---
8.没想到你坚持看到了这里
希望看完这篇文章后你能写一个自己的装饰器,后续我会继续更新,装饰器带参数,和用类写一个装饰器.觉得有帮助请点个推荐吧.
往期精彩:提升Python编程效率的几种方法
深入浅出Python装饰器的更多相关文章
- 关于python装饰器
关于python装饰器,不是系统的介绍,只是说一下某些问题 1 首先了解变量作用于非常重要 2 其次要了解闭包 def logger(func): def inner(*args, **kwargs) ...
- python装饰器通俗易懂的解释!
1.python装饰器 刚刚接触python的装饰器,简直懵逼了,直接不懂什么意思啊有木有,自己都忘了走了多少遍Debug,查了多少遍资料,猜有点点开始明白了.总结了一下解释得比较好的,通俗易懂的来说 ...
- Python 装饰器学习
Python装饰器学习(九步入门) 这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 1 2 3 4 5 6 7 8 # -*- c ...
- python 装饰器修改调整函数参数
简单记录一下利用python装饰器来调整函数的方法.现在有个需求:参数line范围为1-16,要求把9-16的范围转化为1-8,即9对应1,10对应2,...,16对应8. 下面是例子: def fo ...
- python 装饰器学习(decorator)
最近看到有个装饰器的例子,没看懂, #!/usr/bin/python class decorator(object): def __init__(self,f): print "initi ...
- Python装饰器详解
python中的装饰器是一个用得非常多的东西,我们可以把一些特定的方法.通用的方法写成一个个装饰器,这就为调用这些方法提供一个非常大的便利,如此提高我们代码的可读性以及简洁性,以及可扩展性. 在学习p ...
- 关于python装饰器(Decorators)最底层理解的一句话
一个decorator只是一个带有一个函数作为参数并返回一个替换函数的闭包. http://www.xxx.com/html/2016/pythonhexinbiancheng_0718/1044.h ...
- Python装饰器由浅入深
装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码.装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们 ...
- Python装饰器与面向切面编程
今天来讨论一下装饰器.装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数 ...
随机推荐
- P2312 解方程(随机化)
P2312 解方程 随机化的通俗解释:当无法得出100%正确的答案时,考虑随机化一波,于是这份代码很大可能会对(几乎不可能出错). 比如这题:把系数都模一个大质数(也可以随机一个质数),然后O(m)跑 ...
- HTML5学习第四天
HTML5学习第四天 一.HTML列表 HTML列表,有无序表,有序表以及自定义表,列表于列表之间可以实现嵌套 列表相关操作 <ul> <li>(多选)谁世界第二可爱?< ...
- 洛谷P1351 联合权值
\(\Large\textbf{Description:}\) \(\large一棵树,父子之间距离为1,求距离为2的两点点权之积的最大值与和.\) \(\Large\textbf{Solution: ...
- MySQL 批量更新、删除数据shell脚本
#!/bin/bash. ~/.bash_profilelog=/tmp/update_log_1_$(date +%F).logvstart=1step=100vstop=$((${vstart}+ ...
- 数十万PhpStudy用户被植入后门,快来检测你是否已沦为“肉鸡”!
北京时间9月20日,杭州公安发布<杭州警方通报打击涉网违法犯罪暨‘净网2019’专项行动战果>一文,文章曝光了国内知名PHP调试环境程序集成包“PhpStudy软件”遭到黑客篡改并植入“后 ...
- Make the PE file consistent when code not changed
参考:http://www.mouseos.com/assembly/06.html 参考:http://www.cnblogs.com/tk091/archive/2012/04/18/245617 ...
- Angular2的双向数据绑定
什么是双向绑定 如图: 双向绑定.jpg 双向绑定机制维护了页面(View)与数据(Data)的一致性.如今,MVVM已经是前段流行框架必不可少的一部分. Angular2中的双向绑定 双向绑定, ...
- jmeter常见错误及解决方法
jmeter常见错误: 错误一: Response code: Non HTTP response code: java.net.SocketTimeoutException Response m ...
- Window Server 2019 配置篇(5)- 在域中建立WSUS以实现自动更新
上次讲到我们的服务器群中增加了一台用于自动部署的服务器,这次我们要添加一台搭载WSUS服务的服务器,以实现对window更新的管理 那么WSUS是什么服务呢? WSUS是window server u ...
- 20200119日志 EPLAN高压房 VFD 单线图 心得
提纲: EPLAN 画单线图的方法,可以先绘制原理图,然后在一个柜子里面的器件 用方框圈起来.方框名称一样.注意 一个工程里面的器件编号是唯一的. 断路器选型. PT 手车 接地刀作用 具体内 ...