Python3学习(17)--装饰器decorator
来源:互联网 发布:php工程师中国 编辑:程序博客网 时间:2024/06/05 16:19
我们知道,在Python中,函数可以当做参数来使,也可以当做函数的返回值,还可以赋给一个变量,利用变量我们也可以实现函数的功能:
还可以作为序列的元素:
这样一来,我们函数本身也是个对象,针对函数对象,Python为我们提供了其对应的属性,这里我们学习两个属性:
__name__
__doc__
下面,我们直接看下例子demo,根据demo进行注释讲解(这种方法还是比较高效容易理解的):
#/usr/bin/env Python3#-*- encoding:UTF-8 -*-#test.pydef add(*args): """这是一个求和函数,参数可变(不知道有多少个)""" sum = 0 for n in args: sum = sum + n return sumL = [1,2,3,4,5]print(add(*L)) func_name = add.__name__ # 属性:返回 函数名 print('函数名字:',func_name)func_doc = add.__doc__ # 描述:返回 函数描述 print('函数描述:',func_doc)
我们最开始讲函数的时候,说过可变参数,就是一个变量前加一个*号,为了就是,针对不定参数的函数考虑的,如果我们要对一个整数序列进行累加求和,我们就可以构造一个L,传参的时候在L前面加一个*即可,重点不在传参,而是在打印函数的两个属性值:
okey,下面我们就开始来聊一聊今天的主题,什么是装饰器?装饰器是干嘛的,它有什么用?
一、什么是装饰器(decoretor)?
装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。
二、装饰器是干嘛的,有什么用?
抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能,也称之为扩展功能。
我们知道对象可能是一个类,也有可能是个函数,但是,本篇,我们只对函数的扩展部分进行学习,我们用装饰器来扩展函数的功能,同时不改变函数本身的定义(@functools.wraps(func)),我们用事务处理作为场景,来实现一个简单复杂例子(本篇我们先从难道易,循序渐进的吸收装饰器的定义和使用),该例子实现一个简单登陆验证功能,如果选择了验证,我们就判断用户名和密码是否正确,如果正确返回成功状态1,如果失败返回失败状态0,我们先用普通函数的思想设计我们的程序,我们将用户输入信息,是否要开启验证功能以及登录验证三者抽离,我们分成两个函数来实现,demo如下:
#/usr/bin/env Python3#-*- encoding:UTF-8 -*-#test.pydef verification(*args): #是否验证用户名和密码 True or False def login(User,Pwd,**others): nStatu = 0 #登录状态 0:失败 1:成功 if args[0]: print('开启用户和密码验证:') if User == 'appleyk' and Pwd =='123456': print('登录成功!') nStatu = 1 else: print('登录失败!') nStatu = 0 else: print('不开启验证,直接登录!') nStatu = 1 print('用户名:',User,',密码:',Pwd) print('登录过程结束.........') return nStatu return logindef Test_login(User,Pwd,isTrue,**others): f = verification(isTrue) #这个是login函数 nStatu = f(User,Pwd) #这个接收返回的登录状态值 print('登录状态: ',nStatu)Test_login('appleyk','123456',True)
Test_login用来测试用户名appleyk是否密码正确,这个函数如果想自己实现验证功能也可以,只不过所有功能用一个函数来实现,这样的工程耦合度太高,牵一发动全身,不如各个功能抽离出去,需要改动的时候,我们只针对需要的模块进行改动就行,下面我们看下这种方式的实现效果:
上面是用普通的函数封装进行Test_login函数的测试,我们发现,函数Test_login内部必须显示的一层层的调用verification函数才行,如果,我们只想让Test_login提供用户信息参数,其内部什么也不做pass,就能实现上述所有功能的话,我们要怎么做?
由此可见,我们要改进的demo,要具备以下两个特点:
(1)Test_login 函数本身不受影响,它该干嘛干嘛,不能破坏它最开始的定义--什么都不做
(2)扩展Test_login函数功能,以此到达我们的最终功能要求
这个时候,decoretor装饰器便响亮的出场了:
格式:
@de_func #装饰器可以有参数,无参数的话 括号可以不带
def func(*args,**others):
pass #以上写法等同于 func =de_fun(func) 如果带参数就是func = de_fun(arg)(func)
func() #执行func的同时,装饰器也会发挥其作用,将扩展的功能作用在fun运行前后
根据装饰器的格式书写,我们来改进下我们上面的demo,无非就是将功能代码这部分交给装饰器(其实就是一个作用在指定函数身上的函数,起到扩展函数功能的同时,不影响函数本身),我们来看下改后的demo:
#/usr/bin/env Python3#-*- encoding:UTF-8 -*-#decoretor.pyimport functools #导入 functools 模块 def verification(level): #是否验证用户名和密码 True or False def decorator(func): #装饰器 func是要被装饰的 函数 @functools.wraps(func) #我们可以对func进行装饰重写的同时,保持func本身不发生改变 def login(User,Pwd,**others):#针对登录模块 进行判断用户和密码 -- 装饰开始 """Here's a doc login""" nStatu = 0 #登录状态 0:失败 1:成功 if level: print('开启用户和密码验证:') if User == 'appleyk' and Pwd =='123456': print('登录成功!') nStatu = 1 else: print('登录失败!') nStatu = 0 else: print('不开启验证,直接登录!') nStatu = 1 print('用户名:',User,',密码:',Pwd) func(User,Pwd,**others) #这里我们打印最开始func定义的功能,其实执行的就是Test_login,这里是什么也不输出(Pass) print('登录过程结束.........decorator is over!') #func结束后,我们装饰的目的也就结束了 return nStatu #登录判断 返回一下 登录状态值 return login #返回这个装饰效果(登录验证函数--属于扩展功能) return decorator #返回装饰器(包装函数,这个函数在func运行期间,对其进行了扩展) @verification(False) #注意 verification返回的是一个装饰器,这个装饰器对函数Test_login实现功能扩展def Test_login(User,Pwd,**others): """Here's a doc Test_login""" pass n = Test_login('appleyk','123456')print("登录状态:",n)print(Test_login.__name__,',注释标记:',Test_login.__doc__)我们先看下执行结果:
我们说过,装饰器装饰过的函数,要在装饰结束后,前后不发生结构上的改变,正如我们看到的结果,Test_login的name属性到最后依然是Test_login(可能你这会还觉得,这不本来就应该是吗,怎么是依然是,莫非,装饰后,它还可以变?),我们注意到案例demo里面有行代码是这样的:
这行代码至关重要,直接影响被装饰的函数Test_login,我们将其注释掉
然后,我们,再运行demo看看效果:
上面的例子如果半懂的话,证明你对这种装饰的过程已经有了认识,我们反着来,弄一个简单的装饰器玩玩:
#/usr/bin/env Python3#-*- encoding:UTF-8 -*-#test.pyimport functoolsdef decoretor(func): @functools.wraps(func)#注意,我们最后还是要验证run还是不是run def my_run(): #扩展run,在跑之前喊 预备,跑完之后,告知比赛结束 print('预备................') f = func #我们最后返回这个func ,实际上也可以不这样写,直接 return func就行,这里为了展示效果 func() #这里我们开始 跑,实际上执行的是函数run print('比赛结束............') return f #返回 f -- func函数的副本,这里返回的是run函数的副本,功能一模一样,但是但是函数对象的地址不一样 return my_run #返回我们的装饰器(扩展函数) @decoretordef run(): print('跑') #装饰器作用的对象是run这个函数 f =run() #因此,我们执行run函数的同时,我们的装饰器也没闲着,扩展功能将作用在run运行前后print(run) #打印run函数对象的内存地址print(f) #装饰器返回的是一个函数,而这个函数的返回值又是一个函数,这个函数是run函数的功能属性拷贝函数,不==runprint(f.__name__) #无论有没有@functools.wraps(func)限制,这个f始终是run,也就是run的副本print(run.__name__)#run是不是run还要看@functools.wraps(func)这行代码f() #我们运行一下run函数的副本
针对以上以上demo,我们分两种情况来执行输出,一种就是有@functools.wraps(func)修饰,一种是无
A、@functools.wraps(func)
A、#@functools.wraps(func)
装饰器总结:
通过使用装饰器,我们可以很轻松的实现函数的扩展功能,从而不改变函数本身的性质,而装饰器又非常的灵活,稍加设计即可写出来很棒很强大又很有用的功能,来满足我们对于函数的增强。Python 的 decorator 可以用函数实现,也可以用类实现。
- Python3学习(17)--装饰器decorator
- 《设计模式》学习笔记--装饰器Decorator
- Decorator装饰器模式Java示例学习
- Decorator装饰器模式Java示例学习
- Python学习笔记(二) 装饰器decorator
- python3学习笔记:装饰器
- Decorator Pattern(装饰器)
- 装饰器(Decorator)模式
- Decorator装饰器
- 装饰器(Decorator)模式
- 装饰器(Decorator)模式
- 装饰器(Decorator)模式
- 装饰器模式(Decorator)
- 装饰器(Decorator)模式
- Decorator装饰器
- 装饰器-decorator
- Python Decorator(装饰器)
- 装饰器(Decorator)模式
- 前沿IT技术走向未来战场
- Floyd算法
- PL-SQL 编程(三 )程序包和包体,触发器,视图,索引
- Kotlin入门篇(四),如何使用when语句
- ubuntu下的用户名密码修改记录
- Python3学习(17)--装饰器decorator
- poj1185 炮兵阵地(状压Dp)
- Linux2.6内核编译裁剪记录(Kernel panic
- 为自己定的目标
- python scrapy爬取生物谷之模拟登陆(使用FormRequest)
- IDEA的Maven项目整合Spring和Mybatis框架出现ibatis.binding.BindingException: Invalid bound statement (not found)
- HDU 4704 Sum
- 用C++写的项目五子棋(单机,不涉及网络版本)
- Kotlin入门篇(五),Loop和Range,Kotlin中区间的定义和遍历