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网络编程学习笔记(九):数据库客户端 DB-API
Jun 09 Python
django之session与分页(实例讲解)
Nov 13 Python
解析Python中的eval()、exec()及其相关函数
Dec 20 Python
python实现手机通讯录搜索功能
Feb 22 Python
Python实现手写一个类似django的web框架示例
Jul 20 Python
Django模板Templates使用方法详解
Jul 19 Python
python实现socket+threading处理多连接的方法
Jul 23 Python
基于Python2、Python3中reload()的不同用法介绍
Aug 12 Python
在Pytorch中使用样本权重(sample_weight)的正确方法
Aug 17 Python
浅析PEP570新语法: 只接受位置参数
Oct 15 Python
关于Python中定制类的比较运算实例
Dec 19 Python
使用Python 自动生成 Word 文档的教程
Feb 13 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
深入理解curl类,可用于模拟get,post和curl下载
2013/06/08 PHP
PHP加密技术的简单实现
2016/09/04 PHP
javascript文本框内输入文字倒计数的方法
2015/02/24 Javascript
在JavaScript的正则表达式中使用exec()方法
2015/06/16 Javascript
javascript类型系统——日期Date对象全面了解
2016/07/13 Javascript
jquery控制页面的展开和隐藏实现方法(推荐)
2016/10/15 Javascript
jquery css实现邮箱自动补全
2016/11/14 Javascript
angular.js + require.js构建模块化单页面应用的方法步骤
2017/07/19 Javascript
JavaScript上传文件时不用刷新页面方法总结(推荐)
2017/08/15 Javascript
jQuery取得元素标签名称小结(附代码)
2017/08/16 jQuery
JavaScript中Hoisting详解 (变量提升与函数声明提升)
2017/08/18 Javascript
微信小程序模板和模块化用法实例分析
2017/11/28 Javascript
vue如何限制只能输入正负数及小数
2019/07/04 Javascript
vue深度监听(监听对象和数组的改变)与立即执行监听实例
2020/09/04 Javascript
vue中可编辑树状表格的实现代码
2020/10/31 Javascript
写一个Vue loading 插件
2020/11/09 Javascript
原生js实现九宫格拖拽换位
2021/01/26 Javascript
[01:01:18]DOTA2上海特级锦标赛主赛事日 - 2 败者组第二轮#2COL VS LGD
2016/03/03 DOTA
在Python中操作列表之List.pop()方法的使用
2015/05/21 Python
Python中条件判断语句的简单使用方法
2015/08/21 Python
Python中线程的MQ消息队列实现以及消息队列的优点解析
2016/06/29 Python
微信跳一跳python辅助软件思路及图像识别源码解析
2018/01/04 Python
深入理解Python中的 __new__ 和 __init__及区别介绍
2018/09/17 Python
Anaconda+vscode+pytorch环境搭建过程详解
2020/05/25 Python
python与pycharm有何区别
2020/07/01 Python
Bally巴利英国官网:经典瑞士鞋履、手袋及配饰奢侈品牌
2018/05/07 全球购物
全球最大的在线橄榄球商店:Lovell Rugby
2018/05/20 全球购物
软件测试工程师结构化面试题库
2016/11/23 面试题
文明宿舍获奖感言
2014/02/07 职场文书
贷款承诺书范文
2014/05/19 职场文书
教师批评与自我批评(群众路线)
2014/10/15 职场文书
一年级数学上册复习计划
2015/01/17 职场文书
中秋节寄语2015
2015/03/24 职场文书
2015年度绩效考核工作总结
2015/05/27 职场文书
详解使用内网穿透工具Ngrok代理本地服务
2022/03/31 Servers
python pandas 解析(读取、写入)CSV 文件的操作方法
2022/12/24 Python