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操作列表的常用方法分享
Feb 13 Python
简单易懂的python环境安装教程
Jul 13 Python
PyTorch上实现卷积神经网络CNN的方法
Apr 28 Python
python docx 中文字体设置的操作方法
May 08 Python
numpy返回array中元素的index方法
Jun 27 Python
导入tensorflow时报错:cannot import name 'abs'的解决
Oct 10 Python
Python基于class()实现面向对象原理详解
Mar 26 Python
解决pycharm编辑区显示yaml文件层级结构遇中文乱码问题
Apr 27 Python
Python单元测试及unittest框架用法实例解析
Jul 09 Python
python实现简单的五子棋游戏
Sep 01 Python
pandas DataFrame.shift()函数的具体使用
May 24 Python
这样写python注释让代码更加的优雅
Jun 02 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
php实现微信公众号主动推送消息
2015/12/31 PHP
JavaScript的变量作用域深入理解
2009/10/25 Javascript
通过DOM脚本去设置样式信息
2010/09/19 Javascript
纯JS实现五子棋游戏兼容各浏览器(附源码)
2013/04/24 Javascript
jquery选择器-根据多个属性选择示例代码
2013/10/21 Javascript
javascript实例分享---具有立体效果的图片特效
2014/06/08 Javascript
Jquery简单分页实现方法
2015/07/24 Javascript
详解JavaScript的回调函数
2015/11/20 Javascript
jQuery链式调用与show知识浅析
2016/05/11 Javascript
bootstrap制作jsp页面(根据值让table显示选中)
2017/01/05 Javascript
Angular模版驱动表单的使用总结
2018/05/05 Javascript
小程序实现人脸识别功能(百度ai)
2018/12/23 Javascript
详解vue-element Tree树形控件填坑路
2019/03/26 Javascript
Koa 中的错误处理解析
2019/04/09 Javascript
微信小程序中使用echarts的实现方法
2019/04/24 Javascript
微信小程序 bindtap 传参的实例代码
2020/02/21 Javascript
Python中decorator使用实例
2015/04/14 Python
Python的Bottle框架中返回静态文件和JSON对象的方法
2015/04/30 Python
Django查找网站项目根目录和对正则表达式的支持
2015/07/15 Python
在Python程序员面试中被问的最多的10道题
2017/12/05 Python
Python 记录日志的灵活性和可配置性介绍
2018/02/27 Python
Python模拟自动存取款机的查询、存取款、修改密码等操作
2018/09/02 Python
解决Pandas的DataFrame输出截断和省略的问题
2019/02/08 Python
PyTorch之图像和Tensor填充的实例
2019/08/18 Python
阿联酋航空丹麦官方网站:Emirates DK
2019/08/25 全球购物
营业经理岗位职责
2013/11/10 职场文书
自我评价范文点评
2013/12/04 职场文书
大三学习计划书范文
2014/05/02 职场文书
党的群众路线教育实践活动个人承诺书
2014/05/22 职场文书
求职教师自荐书
2014/06/19 职场文书
房屋买卖协议书范本
2014/09/27 职场文书
会计专业求职信范文
2015/03/19 职场文书
Django实现翻页的示例代码
2021/05/24 Python
Java 数组内置函数toArray详解
2021/06/28 Java/Android
SpringMVC 整合SSM框架详解
2021/08/30 Java/Android
Python可视化学习之matplotlib内置单颜色
2022/02/24 Python