python装饰器代码深入讲解
作者:newname 发布时间:2023-08-17 20:59:19
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
,获得返回值inner
给s
,此时的s
就相当于inner
,s()
也就相当于inner()
,所以会输出:
**************
Nice day
这就是一个最简单的装饰器啦,是不是很简单~ 但是我们每次在使用的时候还需要先赋值给一个变量(这里的s),然后再经由s调用,未免违反了丹丹“多一行代码都是累赘”的原则,所以我们再修改一下代码:
def outer(func):
def inner():
print('****************')
func()
return inner
@outer # 用outer装饰say
def say():
print('Nice day')
say() # 调用say函数
我把outer
和say
调换了一下位置,先定义了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.
'''
要注意的是,多个装饰器的执行顺序是从第一个装饰器开始,执行到最后一个装饰器,再执行函数本身。
来源:https://blog.csdn.net/qq_25046261/article/details/79558058


猜你喜欢
- 网页的圆角处理,其实最开始的九宫格的表格处理是挺方便的,只是现在都不用表格布局了,自然就被非法取缔了。呵呵。微软的有VML画圆角,由于只是它
- 注:本文的所有数据请移步—— 参考数据一、水平堆叠图堆叠图其实就是柱状图的一种特殊形式fr
- 本教程中将详细阐述传统的图形设计元素是如何应用在现代(2.0时代)的页面设计中的,然后我将解释为什么它们能流行开来,以及如何、何时、在哪里使
- 设置部分:首先网页登录QQ邮箱设置一些待会儿会用到的参数:首先开启POP3/SMTP和IMAP/SMTP服务,然后生成授权码,然后复制到代码
- 本文为大家分享了解决Mysql存储引擎MyISAM常见问题的方法,供大家参考,具体内容如下一、处理MyISAM存储引擎的表损坏在使用MySQ
- ASP中从数据库读取二进制文件数据代码:<%driver_name1="DRIVER={Microsoft&n
- 本文实例讲述了Python利用正则表达式匹配并截取指定子串及去重的方法。分享给大家供大家参考。具体如下:import repattern=r
- 本文实例讲述了Python常见字符串操作函数。分享给大家供大家参考,具体如下:str.split(' ')1.按某一个字符分
- SOAP.py 客户机和服务器SOAP.py 包含的是一些基本的东西。没有 Web 服务描述语言(Web Services Descript
- 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第四个自然段。以下叙述的脚本包括服务器端脚本和客户端的脚本,服务器端脚本指在服务器上
- 参数解释DataFrame.sort_values(by, &nbs
- 每次在操作数据库的时候最烦的就是根据表单提交的内容写sql语句,特别是字段比较多的时候很麻烦,动不动就容易写错。所以我就写了下面的生成sql
- 在python中使用字典,格式如下:dict={ key1:value1 , key2;value2 ...}在实际访问字典值时的使用格式如
- 首先一起来复习一下死锁的概念:死锁是指两个或者多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。下面我们通过几
- 前言学习一门新的语言肯定是要从他的基本语法开始,语法构成了整个程序设计的基础,从语法中我们也可以看到这门语言的一些特性,但是话说回来,语法这
- 前言:多态的实现必须满足两个前提条件1.继承:多态一定是发生在子类和父类之间2.重写:多态子类重写了父类的方法记住这两点再结合代码示例有助于
- 一、*args的使用方法*args 用来将参数打包成tuple给函数体调用def fun(*arg): print(arg,ty
- 目录1、系统环境,必要知识2、安装python3.6.53、安装Django4、安装uWSGI5、安装nginx6、MySQL安装配置7、编
- 本文实例讲述了Python比较文件夹比另一同名文件夹多出的文件并复制出来的方法。分享给大家供大家参考。具体如下:这个东东本来是做来给公司数据
- 编号标准宗地编码(landCode)所在区段编码(sectCode)1131001BG001G0012131001BG002G0013131