目录

  1. 分析
  2. 总结
  3. 优化

分析

python中支持的特殊语法,在函数上方使用:

1
2
3
@decorator
def func1():
pass

python内部会自动执行 decorator(func1),执行之后,再将结果赋值给func1

也就是说会把 func1这个函数名 当作参数传递给了@后面的函数decorator,相当于func1= 函数名(func1)

对多个函数使用装饰器时,若要进行相同的修改,那么直接修改一个装饰器就可以,而不用对需要修改的每个函数都进行相同的修改。

当需要在某一个功能,或几个很小的功能上实现在原功能的基础上,执行前后添加一些操作,适合直接添加相应的功能;如果是批量对多个函数更改,装饰器的维护成本会更低,效果更好。

总结

  • 实现原理:基于@语法和函数闭包,将原函数封装在闭包中,然后将函数赋值为一个新的函数{内层函数},执行函数时再在内层函数中执行闭包中的原函数。
  • 实现效果:可以在不改变原函数内部代码 和 调用方式的前提下,实现在函数执行和执行扩展功能。
  • 适用场景:多个函数系统统一在执行前后自定义一些功能。
  • 装饰器示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def outer(origin):
def inner(*args, **kwargs):
# 执行前
res = origin(*args, **kwargs) # 调用原来的func函数
# 执行后
return res
return inner


@outer
def func():
pass

func()

优化

通过函数可以获取内部数据

1
2
3
admin()		# 执行函数
admin.__name__ # 输出函数名'admin'字符串
admin.__doc__ # 获取函数注释:这是admin的注释

但被装饰之后,执行的本质上不是原函数了,而是装饰器中的inner了,获取用户名、获取函数注释,获取到的都是inner的函数和注释。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def outer(origin):
def inner(*args, *kwargs):
'''inner的注释'''
# 执行前
res = origin(*args, **kwargs) # 调用原来的func函数
# 执行后
return res
return inner


@outer # 被注释后
def admin():
'''这是admin的注释'''
print('admin')

此时如果希望输出的函数名、注释是原函数admin函数的,而不是inner的。那么需要导入functools

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import functools

def outer(origin):
@functools.wraps(origin)
# inner.__name__ = origin.__name__ inner.__doc__ = origin.__doc__
def inner(*args, *kwargs):
'''inner的注释'''
# 执行前
res = origin(*args, **kwargs) # 调用原来的func函数
# 执行后
return res
return inner


@outer # 被注释后
def admin():
'''这是admin的注释'''
print('admin')