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
猜你喜欢
- 这是解释器设置问题,在设置里找到interpreter 找到合适的目录就可以了。因为重装了python导致pycharm找不到路径了。另外,
- 升级了浏览器到IE9,今天进入公司网站后台突然发现有些页面进不去了,F12调试显示有JS错误:DOM Exception: INVALID_
- MySQL字符集多种多样,下面为列举了其中三种最常见的字符集查看方法,该方法供您参考,希望对学习MySQL数据库能有所启迪。一、查看MySQ
- 背景:pony是公司的首席体验官、首席产品经理。这次在产品峰会上pony将自己平时经验的积累与大家交流,体验较细。这次分享研发管理部,设计中
- 我就废话不多说了,大家还是直接看代码吧~#!/usr/bin/env python# encoding: utf-8''
- 从PHP的5.4.0版本开始,PHP提供了一种全新的代码复用的概念,那就是Trait。Trait其字面意思是”特性”、”特点”,我们可以理解
- 模块化分页1.查询语句块<% 取得当前文件名 temp = Split(request.ServerV
- <html><head><title>过滤空格</title><SCRIPT LANG
- 内容摘要:Cookies的值比ASP其他集合(例如Form和ServerVariables)的值要复杂得多。Cookie是一小块由浏览器存贮
- 读取docx文档使用的包是python-docx1. 安装python-docx包sudo pip install python-docx2
- file_get_contents的超时处理话说,从PHP5开始,file_get_content已经支持context了(手册上写着:5.
- 如何通过PHP实现Des加密算法代码实例注:php7以上不支持了,因为php7去掉了某些函数, 另外变量的{}要改为[]<?phpcl
- 本文实例讲述了Python装饰器用法与知识点。分享给大家供大家参考,具体如下:(1)装饰器含参数,被装饰函数不含(含)参数实例代码如下:im
- 阻塞定义当来自应用程序的第一个连接控制锁而第二个连接需要相冲突的锁类型时,将发生阻塞。其结果是强制第二个连接等待,而在第一个连接上阻塞。不管
- Application对象 Application对象是个应用程序级的对象,用来在所有用户间共享信息,并可以在Web应用程序运行期间持久地保
- 请问,如何在ACCESS数据库和SQL SERVER数据库中查询?
- 我想大多数的人在编写ASP程序的时候,都碰到过类似的错误信息: Error Number -> 
- IIS设置首先打开IIS就不用说了巴第2步右建默认网站属性第3步主目录选项卡点击第3步的配置按钮弹出窗口的设置,至此IIS设置完毕任意编辑器
- 如果你忘记了你的MYSQL的root口令的话,你可以通过下面的过程恢复。1. 向mysqld server 发
- 一、问题描述当用JS调用form的方法submit直接提交form的时候,submit事件不响应。为什么?知道的请回复。类比一下,我用inp