Python编程——修饰器
时间 | 主题 |
1.14(周二)20:00 | 如何快速交付价值-持续交付流水线 |
1.15(周三)20:00 | Python编程-生成器&迭代器 |
在上周三的测试运维试听课程中,芒果给大家介绍了Python编码过程中常用的一种设计模式-修饰器的使用,这里我们来做个小总结。
在开始学习修饰器之前,我们先学习一个关于Python的小概念——高阶函数。
在Python中函数可以作为参数传递给另一个函数,将其他函数作为参数的函数也称为高阶函数。
像我们常用的map、filter、sorted等等都属于高阶函数。
高阶函数示例:
#一个普通函数,返回两个参数的乘积
def my_mul(x,y):
return x*y
#一个普通函数,返回两个参数的和
def my_add(x,y):
return x+y
#一个高阶函数,其参数为函数
def my_func(f):
x = 4
y = 5
result = f(x,y)
print(result)
#主函数
if __name__ == '__main__':
#以my_mul为参数,调用my_func,打印值为两数之乘积
my_func(my_mul)
#以my_add为参数,调用my_func,打印值为两数之和
my_func(my_mul)
高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。
函数作为返回值高阶函数示例:
#一个返回值为闭包函数sum的高阶函数
def my_func01():
def my_sum(*args):
count = 0
for arg in args:
count = count + arg
return count
return my_sum
#主函数
if __name__ == '__main__':
#调用my_func01,得到返回值my_sum函数
f = my_func()
#调用my_sum函数,以获得指定数据的和
result = f(1,3,5,7,9)
print(result)
我们假设这样一种场景:
一段已经存在非常长时间的代码中有几个很是复杂的函数f1、f2、f3...,复杂到看都不想看,反正我们就是不想改这些函数,但是我们需要在这个函数的前后加功能。
假设此处我们想添加的功能是,在函数调用前后,打印当前的时间,以了解函数的运行情况。我们可以尝试以下做法:
# 这里假设我们需要添加功能的函数为test_function,因为内部具体实现我们不关心,所以以一行打印值替代
def test_function():
print("this is a complex function")
def time_about_function(f):
print("before function",time.strftime("%Y-%m-%d %H:%M%S",time.localtime()))
f()
print("after function", time.strftime("%Y-%m-%d %H:%M%S", time.localtime()))
# 函数调用,将所有对test_function的调用改为time_about_function
# test_funciton()
time_about_function()
以上修改的缺点就是所有调用该函数的地方都要进行修改,不利于代码的维护。
这时我们可以引入Python的一个非常高效的设计模式——修饰器。
函数调用前后添加修饰语句,但又不希望修改函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
本质上,修饰器就是一个返回函数的高阶函数。
装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。
以修饰器方式实现以上需求:
# 修饰器函数其实就是一个参数为函数,返回值也为函数额高阶函数
def dec_func(f):
def wrapper():
print("before function", time.strftime("%Y-%m-%d %H:%M%S", time.localtime()))
f()
print("after function", time.strftime("%Y-%m-%d %H:%M%S", time.localtime()))
return wrapper
# 使用修饰器语法来修饰需要增加功能的函数
@dec_func
def test_function():
print("this is a complex function")
# 函数调用,将无需进行任何修改也能实现功能的增加
test_funciton()
上面我们已经完成了对于一个没有参数的函数的功能添加,若这个函数是有参数的,该修饰器就会报错。
针对这种情况,应该如何处理呢?
# 修饰器函数其实就是一个参数为函数,返回值也为函数额高阶函数
def dec_func01(f):
def wrapper(*args,**kwargs):
print("before function", time.strftime("%Y-%m-%d %H:%M%S", time.localtime()))
f(*args,**kwargs)
print("after function", time.strftime("%Y-%m-%d %H:%M%S", time.localtime()))
return wrapper
# 使用修饰器语法来修饰需要增加功能的函数
@dec_func01
def test_function01(x,y):
print("this is a complex function")
print("function has two params:[x:", x, "],[y:", y, "]." )
# 函数调用,任意个数或者任意形式的参数都可以完成正确调用
test_funciton01(x,y)
我们针对以上问题再增加一点难度,如果这个函数式有返回值的应该如何处理呢?
# 修饰器函数其实就是一个参数为函数,返回值也为函数额高阶函数
def dec_func02(f):
def wrapper(*args,**kwargs):
print("before function", time.strftime("%Y-%m-%d %H:%M%S", time.localtime()))
result = f(*args,**kwargs)
print("after function", time.strftime("%Y-%m-%d %H:%M%S", time.localtime()))
return result
return wrapper
# 使用修饰器语法来修饰需要增加功能的函数
@dec_func02
def test_function02(x,y):
print("this is a complex function")
print("function has two params:[x:", x, "],[y:", y, "]." )
return x+y
# 函数调用,可以得其对应的返回值
result = test_funciton02(x,y)
修饰器函数也是函数,那函数也是应该能传参的。函数传参的话,不同的参数可以输出不同的结果。
那么,修饰器函数传参的话,不同的参数会怎么样呢?
# 我们声明一个修饰器,它带有一个参数
def dec_func03(function_name):
def inner(f):
def wrapper(*args,**kwargs):
print("before function", time.strftime("%Y-%m-%d %H:%M%S", time.localtime()))
print("this function name is ",function_name)
result = f(*args,**kwargs)
print("after function", time.strftime("%Y-%m-%d %H:%M%S", time.localtime()))
return result
return wrapper
return inner
# 使用修饰器语法来修饰需要增加功能的函数
@dec_func03("test_function03")
def test_function03(x,y):
print("this is a complex function")
print("function has two params:[x:", x, "],[y:", y, "]." )
return x+y
# 函数调用
result = test_funciton03(x,y)
当然除了课程内容除了这些基本的介绍,还有诸如staticmethod、classmethod和property等内置修饰器、类修饰器等内容。