赞
踩
装饰器是python中非常重要的一个部分,顾名思义就是可以对函数的功能进行装饰扩展。如果有以下需求,可以考虑使用装饰器。
开闭原则:程序设计,要求开放对程序的扩展,关闭对程序的修改。
注: 引入装饰器前,我们需要知道
python可以在函数内定义函数,函数的返回值也可以是函数。
函数名func
不加小括号()
是对函数的调用,不执行;
函数名加小括号func()
表示执行函数,
def func1():
print("零否!")
def func2():
print("源源不断!")
func1()
print("------")
func2()
output:
零否!
------
源源不断!
对函数
func1
和func2
进行扩展,如下:
def func1(): #新函数
print("Hello!")
print("零否!")
print("Bye!")
def func2(): #新函数
print("Hello!")
print("源源不断!")
print("Bye!")
func1()
print("------")
func2()
output:
Hello!
零否!
Bye!
------
Hello!
源源不断!
Bye!
此方法虽然实现了对功能的扩展,如果函数过多时,会非常麻烦,不仅不方便后期维护,且破坏了开闭原则。
对函数扩展,还可创建新函数去调用旧函数,如下
def func1():
print("零否!")
def new_func(): #新函数
print("Hello!")
func1()
print("Bye!")
new_func()
output:
Hello!
零否!
Bye!
此处创建了一个新函数
new_func()
,在new_func()
中调用了函数func1()
,实现了对函数的扩展,满足了开闭原则,但是对多个函数进行扩展时,依旧麻烦,且不易维护!
创建新函数,把旧函数当作新函数的参数传入,如下
def func1(): print("零否!") def func2(): print("源源不断!") def new_func(old_func): #新函数 print("Hello!") old_func() print("Bye!") old_func=func1 new_func(old_func) print("------") old_func=func2 new_func(old_func)
output:
Hello!
零否!
Bye!
------
Hello!
源源不断!
Bye!
此方法和上述方法类似,把函数当作参数(
func
,函数名不加()
)传入,此方法已经接近装饰器的使用。如果传入的函数有参数,此方法不适用,后文会介绍到装饰器装饰(有参函数)
。
文章开篇已经提到
python可以在函数内定义函数,函数的返回值也可以是函数。
def func1(): print("零否!") def func2(): print("源源不断!") def decorate_func(old_func): #装饰器 def new_func(): #新函数 print("Hello!") old_func() print("Bye!") return new_func old_func = func1 #调用函数func1 f1 = decorate_func(old_func) f1() ''' 等同于 decorate_func(func1)() ''' print("------") old_func = func2 #调用函数func2 f2 = decorate_func(old_func) f2() ''' 等同于 decorate_func(func2)() '''
output:
Hello!
零否!
Bye!
------
Hello!
源源不断!
Bye!
此处使用了装饰器,但是不是装饰器经典用法。
@装饰器名 是装饰器的经典用法
以下两种装饰器写法不同,效果相同
写法一,装饰没有返回值的函数
写法二,装饰有返回值的函数,函数没有返回值也可以使用该写法。(经典写法)
#以下两种装饰器写法不同,效果相同 # 写法一,适合没有返回值的函数 def decorate_func(old_func): #装饰器 def new_func(): #新函数 print("Hello!") old_func() print("Bye!") return new_func # 写法二,适合有返回值的函数 # 函数没有返回值也可以使用该写法。 def decorate_func(old_func): #该写法更规范 def new_func(): #新函数 print("Hello!") result = old_func() print("Bye!") return result return new_func @decorate_func #经典用法 @装饰器名 def func1(): print("零否!") @decorate_func #经典用法 @装饰器名 def func2(): print("源源不断!") func1() print("------") func2() ''' 等同于 def func1(): print("零否!") decorate_func(func1)() '''
output:
Hello!
零否!
Bye!
------
Hello!
源源不断!
Bye!
上面介绍了无参装饰器的用法,下面直接介绍有参函数装饰器的用法。
def func3(a, b):
sum = a + b
return sum
def func4(c, d):
mul = c * d
return mul
output:
8
------
18
对已知函数参数列表的函数,进行装饰器扩展,如下
def decorate_func(old_func): def new_func(a,b): print("开始计算:") result = old_func(a,b) #函数执行后返回结果 print("计算结束。") return result return new_func @decorate_func def func3(a, b): sum = a + b return sum f3 = func3(2,6) ''' #等同于 def func3(a, b): sum = a + b return sum decorate_func(func3)(2, 6) ''' @decorate_func def func4(a, b): mul = a * b return mul f4 = func4(3,6) print(f3) print("------") print(f4)
output:
开始计算:
计算结束。
8
------
开始计算:
计算结束。
18
我们知道有些函数有参数,有些函数没有参数,因此我们需要一个,可以装饰
任意函数
(不管有无参数)的装饰器。
python中有可以接收任意参数的关键字
*args
接收元组作为位置参数(任意个)
*kwargs
接收任意个关键字参数(即任意个字典参数)
def decorate_func(old_func): def new_func(*args, **kwargs): #对参数列表进行装包 print("开始计算:") result = old_func(*args, **kwargs) #对参数列表进行拆包 print("计算结束。") return result return new_func @decorate_func def func2(): print("源源不断!") @decorate_func def func3(a, b): sum = a + b return sum func2() print('------') f3 = func3(2, 7) print(f3)
output:
开始计算:
源源不断!
计算结束。
------
开始计算:
计算结束。
9
def decorate_func1(old_func): def new_func(*args, **kwargs): print("装饰器1--hello") result = old_func(*args, **kwargs) print("装饰器1--bye!") return result return new_func def decorate_func2(old_func): def new_func(*args, **kwargs): print("装饰器2--hello") result = old_func(*args, **kwargs) print("装饰器2--bye!") return result return new_func @decorate_func1 @decorate_func2 def func1(): print("零否!") @decorate_func2 @decorate_func1 def func2(): print("源源不断!") func1() ''' #等同于 def func1(): print("零否!") decorate_func1(decorate_func2(func1))() ''' print('------------') func2()
output:
装饰器1--hello
装饰器2--hello
零否!
装饰器2--bye!
装饰器1--bye!
------------
装饰器2--hello
装饰器1--hello
源源不断!
装饰器1--bye!
装饰器2--bye!
从结果可以可以看出,装饰器装饰函数是
由内而外
的,执行顺序是由外而内
的。
@decorate_func2
装饰func1
@decorate_func2
def func1():
print("零否!")
func1()
'''
#等同于
def func1():
print("零否!")
decorate_func2(func1)()
'''
output:
装饰器2--hello
零否!
装饰器2--bye!
@decorate_func1
装饰 (@decorate_func2
装饰func1
的结果)
@decorate_func1
@decorate_func2
def func1():
print("零否!")
func1()
'''
#等同于
def func1():
print("零否!")
decorate_func1(decorate_func2(func1))()
'''
output:
装饰器1--hello
装饰器2--hello
零否!
装饰器2--bye!
装饰器1--bye!
给装饰器传入参数
def decorate_param(param): # 装饰器传入参数 def decorate_func(old_func): # 装饰器传入函数 def new_func(*args, **kwargs): print("hello") print(f"装饰器参数:{param}") # 装饰器参数param result = old_func(*args, **kwargs) print("bye!") return result return new_func return decorate_func @decorate_param("零否") def func(a, b): sum = a + b print(f'{a} + {b} = {sum}') return sum func(1, 2) ''' #等同于 def func(a, b): sum = a + b print(f'{a} + {b} = {sum}') return sum decorate_param("零否")(func)(1,2) '''
output:
hello
装饰器参数:零否
1 + 2 = 3
bye!
文章中如有发现问题或错误,可以留言指正,谢谢!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。