文章目录
前言
Python中的装饰器是一种高级编程技巧,它允许程序员在不修改原有代码的情况下,对函数或类进行功能的增强或修改。装饰器本质上是一个函数,它接收一个函数作为参数,并返回一个新的函数,新函数可以对原函数进行修饰。
1、需求及实现方案
1.1 需求描述
在不修改函数源码的情况下,请在以下函数执行前和执行后分别输入before和after。
def func():
print('我是func函数')
value = (11, 22, 33, 44)
return value
result = func() # 我是func函数
print(result) # (11, 22, 33, 44)
1.2 实现方案
def func():
print('我是func函数')
value = (11, 22, 33, 44)
return value
def outer(origin):
def inner():
print('before')
res = origin() # 调用原来的func函数
print('after')
return res
return inner # 注意,inner后没有括号
func = outer(func) # 将func函数作为参数传进outer函数中,得到新的func函数【本质上是outer函数 return 的 inner】
result = func() # 执行func函数【非原始的func函数,实质上执行inner函数】,并将结果返回给result
print(result)
输出结果:
before
我是func函数
after
(11, 22, 33, 44)
1.3 python中的@函数名
def outer(origin):
def inner():
print('before')
res = origin() # 执行原函数
print('after')
return res
return inner # 注意,inner后没有括号
"""
python中支持特殊语法,在某个函数上方使用:
@函数名
def xxx():
pass
python内部会自动执行 函数名(xxx),执行之后,再将结果赋值给xxx,即:
xxx= 函数名(xxx)
"""
@outer
def func():
print('我是func函数')
value = (11, 22, 33, 44)
return value
result = func()
print(result)
2、装饰器的应用(多个函数)
def outer(origin):
def inner():
print('before')
res = origin() # 执行原函数
print('after')
return res
return inner # 注意,inner后没有括号
@outer
def func1():
print('我是func1函数')
value = (11, 22, 33, 44)
return value
@outer
def func2():
print('我是func2函数')
value = (11, 22, 33, 44)
return value
@outer
def func3():
print('我是func3函数')
value = (11, 22, 33, 44)
return value
func1() # 我是func1函数
func2() # 我是func2函数
func3() # 我是func3函数
总结:如果对与修改的函数比较少,只是需要对函数的前后增加一部分功能,可以直接修改原函数;如果我们需要修改的原函数比较多,我们可以通过装饰器(对函数进行装饰,不改变内部结构)的方式进行增加函数功能。
3、装饰器优化支持多个参数
def outer(origin):
# inner函数中添加参数:*args, **kwargs,支持动态参数;
def inner(*args, **kwargs):
print('before')
res = origin(*args, **kwargs) # 执行原函数
print('after')
return res
return inner # 注意,inner后没有括号
@outer
def func1(a1):
print('我是func1函数')
value = (11, 22, 33, 44)
return value
@outer
def func2(a1, a2):
print('我是func2函数')
value = (11, 22, 33, 44)
return value
@outer
def func3(a1, a2, a3):
print('我是func3函数')
value = (11, 22, 33, 44)
return value
func1(1)
func2(1, 2)
func3(1, 2, 3)
4、装饰器知识点扩展
4.1 __name__
和__doc__
def outer(origin):
def inner(*args, **kwargs):
"""这是一条测试备注信息"""
print('before')
res = origin(*args, **kwargs) # 执行原函数
print('after')
return res
return inner # 注意,inner后没有括号
@outer
def func1(a1):
print('我是func1函数')
value = (11, 22, 33, 44)
return value
# 没有用装饰器
# print('没有用装饰器:', func1.__name__) # 没有用装饰器: func1
# print('没有用装饰器:', func1.__doc__) # 没有用装饰器: None
# 用了装饰器后
print('用装饰器后:', func1.__name__) # 用装饰器后: inner
print('用装饰器后:', func1.__doc__) # 用装饰器后: 这是一条测试备注信息
4.2 functools
在装饰器中的应用
import functools
# 模版代码,务必记住
def outer(origin):
@functools.wraps(origin) # inner.__name__ = origin.__name__ inner.__doc__ = origin.__doc__
def inner(*args, **kwargs):
"""这是一条测试备注信息"""
print('before')
res = origin(*args, **kwargs) # 执行原函数
print('after')
return res
return inner # 注意,inner后没有括号
@outer
def func1(a1):
"""我用了functools"""
print('我是func1函数')
value = (11, 22, 33, 44)
return value
# 用了装饰器后
print('用装饰器后:', func1.__name__) # 用装饰器后: func1
print('用装饰器后:', func1.__doc__) # 用装饰器后: 我用了functools
5 总结
- 实现原理:基于@语法和函数闭包,将原函数封装在闭包中,然后将函数赋值为一个新的函数(内层函数),执行函数时再在内层函数中执行闭包中的原函数;
- 实现效果:可以在不改变原函数内部代码 和 调用方式的前提下,实现在函数执行和执行扩展功能;
- 适用场景:多个函数系统统一在 执行前、执行后自定义一些功能;
- 示例模版代码详见4.2。