目录
介绍装饰器装饰函数如何使用,会 源源不断更新。
python装饰器简介
装饰器是python中非常重要的一个部分,顾名思义就是可以对函数的功能进行装饰扩展。如果有以下需求,可以考虑使用装饰器。
- 对多个函数进行相同功能的扩展
- 方便后期维护
- 遵循开闭原则(OCP)
开闭原则:程序设计,要求开放对程序的扩展,关闭对程序的修改。
注: 引入装饰器前,我们需要知道
python可以在函数内定义函数,函数的返回值也可以是函数。
函数名func
不加小括号()
是对函数的调用,不执行;
函数名加小括号func()
表示执行函数,
装饰器装饰(无参函数)
普通函数
def func1():
print("零否!")
def func2():
print("源源不断!")
func1()
print("------")
func2()
output:
零否!
------
源源不断!
函数扩展1(修改原函数)
对函数
func1
和func2
进行扩展,如下:
def func1(): #新函数
print("Hello!")
print("零否!")
print("Bye!")
def func2(): #新函数
print("Hello!")
print("源源不断!")
print("Bye!")
func1()
print("------")
func2()
output:
Hello!
零否!
Bye!
------
Hello!
源源不断!
Bye!
此方法虽然实现了对功能的扩展,如果函数过多时,会非常麻烦,不仅不方便后期维护,且破坏了开闭原则。
函数扩展2(新函数去调用旧函数)
对函数扩展,还可创建新函数去调用旧函数,如下
def func1():
print("零否!")
def new_func(): #新函数
print("Hello!")
func1()
print("Bye!")
new_func()
output:
Hello!
零否!
Bye!
此处创建了一个新函数
new_func()
,在new_func()
中调用了函数func1()
,实现了对函数的扩展,满足了开闭原则,但是对多个函数进行扩展时,依旧麻烦,且不易维护!
函数扩展3(旧函数当作新函数的参数)
创建新函数,把旧函数当作新函数的参数传入,如下
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
,函数名不加()
)传入,此方法已经接近装饰器的使用。如果传入的函数有参数,此方法不适用,后文会介绍到装饰器装饰(有参函数)
。
函数扩展4(引入装饰器)
文章开篇已经提到
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!
此处使用了装饰器,但是不是装饰器经典用法。
函数扩展5(装饰器经典用法)
@装饰器名 是装饰器的经典用法
以下两种装饰器写法不同,效果相同
写法一,装饰没有返回值的函数
写法二,装饰有返回值的函数,函数没有返回值也可以使用该写法。(经典写法)
#以下两种装饰器写法不同,效果相同
# 写法一,适合没有返回值的函数
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
装饰器1(已知参数列表)
对已知函数参数列表的函数,进行装饰器扩展,如下
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
装饰器2(任意参数列表)
我们知道有些函数有参数,有些函数没有参数,因此我们需要一个,可以装饰
任意函数
(不管有无参数)的装饰器。
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!
文章中如有发现问题或错误,可以留言指正,谢谢!