python装饰器代码深入讲解


Posted in Python onMarch 01, 2021

python装饰器就是用于扩展原函数功能的一种函数,这个函数特殊的地方就是它的返回值也是一个函数,使用Python装饰器的一个好处就是:在不需要修改原函数代码的情况下,给函数增加新的功能。

先来看个例子:

def say():
 print('Nice day')

say()
# 这个函数的输出为:
Nice day

现在,我想在输出Nice day的前面再打印一行****************,类似下面的效果:

**************** 

Nice day

一般情况下,我可以修改上面的代码:

def say():
 print('****************')
 print('Nice day')

say()

可是,如果我忽然发现自己看错了需求,这时候又要把代码修改到原来的样子,庆幸的是我只是在原来函数的基础上增加了一行代码,想要回到原来的状态并不难,可如果我是修改了复杂的逻辑,代码有一百行呢,难道我还要一步步撤销吗?显然做不到,不过没关系,肯定还有别的办法:

def say():
 print('Nice day')

def outer(): # 重新定义一个新函数
 print('****************') # 处理新的逻辑
 say() # 再调用原来的函数

outer()
# 现在的输出为:
'''
****************
Nice day
'''

怎么样,看上去已经满足要求了吧,不过仔细一看,就能发现新的问题,如果不仅仅是say()函数需要打印****************,新来的talk()函数也需要呢,这时候我又要再写一个outer()函数吗?这会累坏丹丹的,所以得再想个办法:

def say():
 print('Nice day')

def talk():
 print('I am talk')

def outer(func): # 接收一个函数
 print('****************') # 处理新的逻辑
 func() # 调用传递过来的函数

outer(talk) # 把talk函数作为参数传递过去
# 输出结果如下:
'''
****************
I am talk
'''

这时,不管有几个函数需要打印****************,我直接把函数名传给outer()就可以啦,是不是方便很多^-^ 但是勤劳的丹丹会止步于此吗?肯定不会,于是又把代码做了如下修改:

def say():
 print('Nice day')

def outer(func):
 def inner():
 print('****************')
 func() # 相当于 say()
 return inner

s = outer(say) # 相当于 s = inner
s() # 相当于 inner()

猜猜这次的是输出是什么~当然还是和上面一样啦!其实这里只是把处理逻辑的部分封装在了一个函数里面,调用outer(say)的时候,把say传给outer,获得返回值inners,此时的s就相当于inners()也就相当于inner()所以会输出:

**************

Nice day

这就是一个最简单的装饰器啦,是不是很简单~ 但是我们每次在使用的时候还需要先赋值给一个变量(这里的s),然后再经由s调用,未免违反了丹丹“多一行代码都是累赘”的原则,所以我们再修改一下代码:

def outer(func):
 def inner():
 print('****************')
 func()
 return inner

@outer # 用outer装饰say
def say():
 print('Nice day')

say() # 调用say函数

我把outersay调换了一下位置,先定义了outer函数,@outer表示用outer装饰say,这样直接用say()就能实现我想先打印一行****************的功能了,如果不调换两个函数的位置,是会报NameError: name 'outer' is not defined的错误的噢(作用域的原因,outer未定义),这个应该算是复杂一点的装饰器了吧,哈哈
这时候很多细心同学肯定就会问了,你写的都是无参的呀,那如果我的函数有参数怎么办呢,参数还是不固定的又该怎么办呢?万能的python+聪明的丹丹当然可以解决:

# 带参数的装饰器
def outer(func):
 def inner(name):
 func(name)
 return inner

@outer
def say(name):
 print('name is %s.' % (name))

say('dandan')
# name is dandan.

不过这个参数个数是固定的,万一我又突发奇想,想多传一个hobby或者age怎么办呢?

# 带不定参数的装饰器
def outer(func):
 def inner(*args, **kwargs):
 func(*args, **kwargs)
 return inner

@outer
def say(name, age):
 print('name is %s, age is %d.' % (name, age))

@outer
def talk(name, age, hobby):
 print('name is %s, age is %d, hobby is %s.' % (name, age, hobby))

say('dandan', 18)
talk('dandan', 18, 'Coding')
'''
name is dandan, age is 18.
name is dandan, age is 18, hobby is Coding.
'''

如果我要新增的功能有很多,一个装饰器搞不定,怎么办呢?我可以同时使用多个装饰器吗?当然可以:

# 多个装饰器
def outer(func):
 def inner(*args, **kwargs):
 print('****************')
 func(*args, **kwargs)
 return inner

def outer2(func):
 def inner2(*args, **kwargs):
 print('这里有1w+新功能')
 func(*args, **kwargs)
 return inner2

@outer
@outer2
def say(name, age):
 print('name is %s, age is %d.' % (name, age))

@outer
@outer2
def talk(name, age, hobby):
 print('name is %s, age is %d, hobby is %s.' % (name, age, hobby))

say('dandan', 18)
talk('dandan', 18, 'Coding')
'''
****************
这里有1w+新功能
name is dandan, age is 18.
****************
这里有1w+新功能
name is dandan, age is 18, hobby is Coding.
'''

要注意的是,多个装饰器的执行顺序是从第一个装饰器开始,执行到最后一个装饰器,再执行函数本身。

到此这篇关于python装饰器代码深入讲解的文章就介绍到这了,更多相关python装饰器内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python中使用urllib2伪造HTTP报头的2个方法
Jul 07 Python
Python中str is not callable问题详解及解决办法
Feb 10 Python
Django forms组件的使用教程
Oct 08 Python
Python中staticmethod和classmethod的作用与区别
Oct 11 Python
python utc datetime转换为时间戳的方法
Jan 15 Python
python+pyqt5实现KFC点餐收银系统
Jan 24 Python
Python叠加两幅栅格图像的实现方法
Jul 05 Python
python中类的输出或类的实例输出为这种形式的原因
Aug 12 Python
Python制作简易版小工具之计算天数的实现思路
Feb 13 Python
Django生成数据库及添加用户报错解决方案
Oct 09 Python
python 爬虫如何实现百度翻译
Nov 16 Python
python - timeit 时间模块
Apr 06 Python
Pytorch如何切换 cpu和gpu的使用详解
Mar 01 #Python
python爬取股票最新数据并用excel绘制树状图的示例
Mar 01 #Python
python中openpyxl和xlsxwriter对Excel的操作方法
Mar 01 #Python
python中random模块详解
Mar 01 #Python
利用python实现汉诺塔游戏
Mar 01 #Python
python绘制汉诺塔
Mar 01 #Python
彻底解决pip下载pytorch慢的问题方法
Mar 01 #Python
You might like
基于MySQL到MongoDB简易对照表的详解
2013/06/03 PHP
php采集自中央气象台范围覆盖全国的天气预报代码实例
2015/01/04 PHP
php创建session的方法实例详解
2015/01/27 PHP
跟着JQuery API学Jquery 之三 筛选
2010/04/09 Javascript
jquery方法+js一般方法+js面向对象方法实现拖拽效果
2012/08/30 Javascript
同域jQuery(跨)iframe操作DOM(实例讲解)
2013/12/19 Javascript
js获取当前地址 JS获取当前URL的示例代码
2014/02/26 Javascript
在Google 地图上实现做的标记相连接
2015/01/05 Javascript
JavaScript实现基于Cookie的存储类实例
2015/04/10 Javascript
jquery实现像栅栏一样左右滑出式二级菜单效果代码
2015/08/24 Javascript
基于jQuery实现在线选座之高铁版
2015/08/24 Javascript
js实现的页面加载完毕之前loading提示效果完整示例【附demo源码下载】
2016/08/02 Javascript
Angularjs中controller的三种写法分享
2016/09/21 Javascript
原生js实现查询天气小应用
2016/12/09 Javascript
AngularJS之页面跳转Route实例代码
2017/03/10 Javascript
addeventlistener监听scroll跟touch(实例讲解)
2017/08/04 Javascript
微信小程序实现复选框效果
2018/12/28 Javascript
微信小程序生成海报分享朋友圈的实现方法
2019/05/06 Javascript
Vue中nprogress页面加载进度条的方法实现
2020/11/13 Javascript
pyqt4教程之实现windows窗口小示例分享
2014/03/07 Python
详解多线程Django程序耗尽数据库连接的问题
2018/10/08 Python
python hook监听事件详解
2018/10/25 Python
Python txt文件加入字典并查询的方法
2019/01/15 Python
python启动应用程序和终止应用程序的方法
2019/06/28 Python
python中比较两个列表的实例方法
2019/07/04 Python
对Python中一维向量和一维向量转置相乘的方法详解
2019/08/26 Python
Python爬取腾讯视频评论的思路详解
2019/12/19 Python
PyTorch 普通卷积和空洞卷积实例
2020/01/07 Python
详解Python中的分支和循环结构
2020/02/11 Python
幼儿园元旦亲子活动方案
2014/02/17 职场文书
人民教师的自我评价分享
2014/02/21 职场文书
献爱心大型公益活动策划方案
2014/09/15 职场文书
员工工作自我评价
2014/09/26 职场文书
2014年小学数学工作总结
2014/12/12 职场文书
大学生求职自荐信范文
2015/03/04 职场文书
MATLAB 如何求取离散点的曲率最大值
2021/04/16 Python