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实现将16进制字符串转化为ascii字符的方法分析
Jul 21 Python
Python排序搜索基本算法之堆排序实例详解
Dec 08 Python
python 筛选数据集中列中value长度大于20的数据集方法
Jun 14 Python
Python图像处理之图像的缩放、旋转与翻转实现方法示例
Jan 04 Python
python ipset管理 增删白名单的方法
Jan 14 Python
Python 按字典dict的键排序,并取出相应的键值放于list中的实例
Feb 12 Python
python利用跳板机ssh远程连接redis的方法
Feb 19 Python
Python中的上下文管理器相关知识详解
Sep 19 Python
pandas将多个dataframe以多个sheet的形式保存到一个excel文件中
Oct 10 Python
python中seaborn包常用图形使用详解
Nov 25 Python
windows10环境下用anaconda和VScode配置的图文教程
Mar 30 Python
解决virtualenv -p python3 venv报错的问题
Feb 05 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编程最快明白》第三讲:php数组
2010/11/01 PHP
php ctype函数中文翻译和示例
2014/03/21 PHP
非常好用的Zend Framework分页类
2014/06/25 PHP
PHP实现小偷程序实例
2016/10/31 PHP
php实现简单的权限管理的示例代码
2017/08/25 PHP
ThinkPHP3.2框架自带分页功能实现方法示例
2019/05/13 PHP
JQuery 文本框使用小结
2010/05/22 Javascript
js 调用本地exe的例子(支持IE内核的浏览器)
2012/12/26 Javascript
jquery实现简单的拖拽效果实例兼容所有主流浏览器
2013/06/21 Javascript
thinkphp中常用的系统常量和系统变量
2014/03/05 Javascript
Angular的自定义指令以及实例
2016/12/26 Javascript
angular6.0使用教程之父组件通过url传递id给子组件的方法
2018/06/30 Javascript
详解如何制作并发布一个vue的组件的npm包
2018/11/10 Javascript
详解vue 兼容IE报错解决方案
2018/12/29 Javascript
详解vue路由篇(动态路由、路由嵌套)
2019/01/27 Javascript
Javascript迭代、递推、穷举、递归常用算法实例讲解
2019/02/01 Javascript
vue中各种通信传值方式总结
2019/02/14 Javascript
微信小程序渲染性能调优小结
2019/07/30 Javascript
layui-table对返回的数据进行转变显示的实例
2019/09/04 Javascript
vue实现的多页面项目如何优化打包的步骤详解
2020/07/19 Javascript
浅析微信小程序自定义日历组件及flex布局最后一行对齐问题
2020/10/29 Javascript
vue使用element-ui实现表单验证
2020/12/13 Vue.js
django文档学习之applications使用详解
2018/01/29 Python
Django使用redis缓存服务器的实现代码示例
2019/04/28 Python
HTML的form表单和django的form表单
2019/07/25 Python
Python使用grequests(gevent+requests)并发发送请求过程解析
2019/09/25 Python
详解python内置常用高阶函数(列出了5个常用的)
2020/02/21 Python
英国儿童图书网站:Scholastic
2017/03/26 全球购物
node中使用shell脚本的方法步骤
2021/03/23 Javascript
我的画教学反思
2014/04/28 职场文书
幼儿园教师师德师风演讲稿:我自豪我是一名幼师
2014/09/10 职场文书
祖国在我心中演讲稿(小学生)
2014/09/23 职场文书
财务工作失职检讨书
2014/11/21 职场文书
学雷锋倡议书
2015/01/19 职场文书
院系推荐意见
2015/06/05 职场文书
Python实现查询剪贴板自动匹配信息的思路详解
2021/07/09 Python