提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
在学习python的过程中,会学习到装饰器的使用,装饰器在python中是一个非常重要的存在,可以减少大量的冗余代码,python中存在部分第三方的装饰器,可以直接使用,也可以自己去写一部分装饰器,如果用过pytest 接口自动化测试框架的小伙办,其中fixture 就是一个很典型的第三方装饰,其中fixture的使用方式就是符合装饰器的使用,感兴趣的小伙伴可以看看小编以前的文章,本篇文章小编带领大家手动一个简单的装饰器。
提示:以下是本篇文章正文内容,下面案例可供参考
一、什么是装饰器
装饰器的本质是一个函数或者类,它可以让其他函数和类不需要做任何修改的前提下额外增加新的功能,装饰器的返回值也是一个函数/类对象,可以给其他函数直接使用。
二、装饰器编写-无参数
情景:如果有一个函数已经编写完成,需要收集一下函数的运行时间,咱们再实现该功能时,可以再每一个函数中添加两行代码,用来输出运行时间
1.原始函数
- 原始代码如下:
def fun_c():
print ("hello_word_fun_c")
time.sleep(5)
- 收集函数运行时间,尝试使用再每一个函数中添加
def fun_c():
print ("hello_word_fun_c")
# 获取开始时间
start = time.time()
time.sleep(5)
end = time.time()
print ("运行时间:%.4f" % (end - start))
运行结果:
3. 那如果存在多个函数时,每个函数去添加代码就显得有点不那么机智了,此时就可以使用装饰器函数来实现,只需要写一个装饰器函数,后面的函数使用该装饰器就可以了,详情如下:
# 编写装饰器
def run_time1(fun):
def run():
# 装饰器的内部实现,同时需要再外函数处return 内函数
start = time.time()
f = fun()
end = time.time()
print ("运行时间:%.4f" %(end-start))
return f
return run
# 使用装饰器函数
@run_time
def fun_a():
print ("hello_word_fun_a")
time.sleep(3)
# 使用装饰器函数
@run_time
def fun_b():
print ("helo_word_fun_b")
time.sleep(2)
# 调用函数自测
if __name__=="__main__":
fun_a()
fun_b()
测试结果截图:
2.装饰器编写-可变参数(位置参数/关键字参数)
由上面编写的装饰器联想,目前的装饰器是没有任何参数传递的,那如果使用的函数需要传参怎么办呢? 参数要是可变的该如何处理呢?别慌,小编也想到该种情况了,联想到python中的可变参数传递,*args,**kwargs 的方式,然后再和装饰器结合,就可以实现咱们的问题,代码如下:
# 装饰器添加可变参数
def run_time1(fun):
# 添加可变参数 *args , **kwargs
def run(*args , **kwargs):
# 装饰器的内部实现,同时需要再外函数处return 内函数
start = time.time()
f = fun(*args, **kwargs)
end = time.time()
print ("运行时间:%.4f" %(end-start))
return run
# 使用位置参数,实现传递可变参数
@run_time1
def fun_a(*args):
print ("hello_word_fun_a")
print (type(args))
print (args)
time.sleep(3)
# 使用关键字参数,实现传递可变参数
@run_time1
def fun_b(**kwargs):
print ("hello_word_fun_b")
print (type(kwargs))
print (kwargs)
time.sleep(2)
# 调用函数自测
if __name__=="__main__":
fun_a("zhangsan","lisi")
fun_b(name= "zhangsan", age = 10)
自测结果:
3.装饰器的原理
3.1 装饰器遵循的原则
- 不修改被装饰对象的源代码(即不修改代码示例中的fun_a().fun_b()函数)
- 装饰器本身可以是任意可以调用的对象
3.2 装饰器的原理 - 装饰器的内部是使用了闭包函数,把新增加的逻辑写在了闭包函数中,在运行程序时,使用了装饰器的函数会自动调用装饰器函数返回的对象,且执行装饰器中的逻辑,那么什么是闭包函数呢?简单来说
- 定义再一个函数体内的函数,并且内部函数由对外部作用域名字的引用。
- 闭包无法修改外部函数的局部变量
- 闭包可以保存当前的运行环境
可参考:闭包函数
4. 手写装饰器的步骤
装饰器的编写
4.1 定义两个函数,一个内层函数,一个外层函数有一个形参,来接受被装饰的函数对象
4.2 在内置函数中添加装饰器的逻辑,并且引用外部函数的作用域名的引用
4.3 在外层函数中 return 内层函数
装饰器的使用
4.4 在需要使用装饰器的函数外面,使用@函数名。
装饰器代码注释:
# 外层函数,外层函数使用形参fun,来接受被装饰的函数对象
def run_time(fun):
# 定义内层函数
def run():
# 在内置函数中引用外部函数的作用域名字
f = fun()
# 装饰器的内部实现,
start = time.time()
end = time.time()
print ("运行时间:%.4f" %(end-start))
# 在外层函数中return 内层函数
return run
# 使用@外层函数名来调用装饰器
@run_time
def fun_a():
print ("hello_word_fun_a")
time.sleep(3)
5. python的可变参数传递
由上述中描写的装饰器传递可变参数的例子,小编简单总结一下在python中如何传递可变参数。一共有两种方式,位置参数和关键字参数,具体使用方法如下:
5.1 位置参数(args)
位置参数在函数调用的过程中可以传递多个参数,形参使用args 格式(其中* 时必填,args 为关键字,可修改为其他可读性关键字),使用位置参数的函数,会把收集到的参数转换成元组,并且按着传递顺序放在元组中,例子如下:
def Sum(* args):
print (type(args))
print args
sum2 = 0
for i in args:
sum2+= i
return sum2
# 自测函数
if __name__=="__main__":
sum1 = Sum(1,2,3,4)
自测结果:
**5.1 关键字参数(kwargs)
关键字参数在调用时使用key+values 的形式传递多个参数,形参使用 kwargs 格式定义(其中 时必填,kwargs 为关键字,可修改为其他可读性高的关键字) ,函数会把收集到的参数变成字典格式,以key-vaue的形式输出,后面如果使用该参数,直接进行使用即可。
# 关键字参数
def kw(** kw):
print (type(kw))
# 读取字典中的key值为name的values值
print ("获取登录用户名:%s" % (kw['name']))
print kw
# 输出字典中的所有key值
print kw.keys()
# 自测函数
if __name__=="__main__":
kw1= kw(name = "zhangxioyan", age = 18)
自测结果:
总结
以上是今天小编整理的python-装饰器的原理和编写方式,如果有什么补充欢迎大家留言奥。