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 相关文章推荐
Apache如何部署django项目
May 21 Python
python实现扫描日志关键字的示例
Apr 28 Python
python提取图像的名字*.jpg到txt文本的方法
May 10 Python
Python 实现遥感影像波段组合的示例代码
Aug 04 Python
解决python 3 urllib 没有 urlencode 属性的问题
Aug 22 Python
Numpy之reshape()使用详解
Dec 26 Python
mac 上配置Pycharm连接远程服务器并实现使用远程服务器Python解释器的方法
Mar 19 Python
python 实现两个线程交替执行
May 02 Python
python软件都是免费的吗
Jun 18 Python
解决导入django_filters不成功问题No module named 'django_filter'
Jul 15 Python
Python 如何在字符串中插入变量
Aug 01 Python
浅谈pytorch中stack和cat的及to_tensor的坑
May 20 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
德生PL550的电路分析
2021/03/02 无线电
PHP系列学习之日期函数使用介绍
2012/08/18 PHP
基于curl数据采集之正则处理函数get_matches的使用
2013/04/28 PHP
php + ajax 实现的写入数据库操作简单示例
2020/05/16 PHP
jquery validate.js表单验证的基本用法入门
2010/05/13 Javascript
Jquery 的扩展方法总结
2011/10/01 Javascript
关于textarea提交的内容无法换行的解决办法
2013/04/09 Javascript
jquery实现的一个文章自定义分段显示功能
2014/05/23 Javascript
express的中间件cookieParser详解
2014/12/04 Javascript
使用Jquery实现每日签到功能
2015/04/03 Javascript
js实现Select头像选择实时预览代码
2015/08/17 Javascript
Bootstrap实现默认导航栏效果
2020/09/21 Javascript
jQuery+json实现动态创建复杂表格table的方法
2016/10/25 Javascript
详解ECharts使用心得总结
2016/12/06 Javascript
js实现for循环跳过undefined值示例
2019/07/02 Javascript
解决layui-open关闭自身窗口的问题
2019/09/10 Javascript
js实现一款简单踩白块小游戏(曾经很火)
2019/12/02 Javascript
使用JavaScript实现贪吃蛇游戏
2020/09/29 Javascript
python中使用xlrd、xlwt操作excel表格详解
2015/01/29 Python
python 开发的三种运行模式详细介绍
2017/01/18 Python
Python通过paramiko远程下载Linux服务器上的文件实例
2018/12/27 Python
python中提高pip install速度
2020/02/14 Python
Pygame的程序开始示例代码
2020/05/07 Python
tensorflow实现从.ckpt文件中读取任意变量
2020/05/26 Python
浅析Python 抽象工厂模式的优缺点
2020/07/13 Python
如何开发一款堪比APP的微信小程序(腾讯内部团队分享)
2016/12/22 HTML / CSS
HTML5中判断用户是否正在浏览页面的方法
2014/05/03 HTML / CSS
丝芙兰中国官方商城:SEPHORA中国
2018/01/10 全球购物
Merrell美国官网:美国登山运动鞋品牌
2018/02/07 全球购物
super关键字的用法
2012/04/10 面试题
绿色环保口号
2014/06/12 职场文书
艺术学院毕业生自荐信
2014/07/05 职场文书
关于感恩的作文
2019/08/26 职场文书
Vue通过懒加载提升页面响应速度
2021/05/10 Vue.js
PYTHON使用Matplotlib去实现各种条形图的绘制
2022/03/22 Python
Java Spring Boot请求方式与请求映射过程分析
2022/06/25 Java/Android