参考:https://blog.csdn.net/zhouchen1998/article/details/82933893

在python语言中,参数含有函数名的函数称之为高阶函数。(此时调用的函数不加参数,也就是说没有括号紧跟)
在不改变源代码的基础上扩展函数需要的新需求,这就是装饰器。(不改变函数源代码,这也是装饰器最基本的原则)
装饰器,它本身也就是一个函数,应用高阶函数实现。
使用时一般把被装饰的函数的内存地址当参数传入装饰器函数体,通过参数调用被装饰的函数,获得或者修改其属性。
一般认为,装饰器使用遵循一定格式,即:高阶函数+高阶函数内嵌套函数。
假设有一个需求,我要知道正在运行什么函数,在运行时输出。
有一个比较粗暴的方法。
# 可以直接在函数中定义
def func1():
print(func1.__name__)
pass
def func2():
print(func2.__name__)
pass
if __name__ == '__main__': #在另一篇文章提到这个,即保证只在该程序运行,不会在import中运行以下。http://t.csdn.cn/U3H1i
func1()
func2()
这一定是对的,但是不自然就想到两个字“封装”,虽然这和装饰器大相径庭,但是两个概念确实有相通之处。
按照装饰器原则,可以这样写。
这里需要注意的是,在装饰器定义的时候,return时不加括号。具体原因见:http://t.csdn.cn/uMdqd
# 使用装饰器
def zhuang_shi_qi(func):
def out():
func()
print(func.__name__)
return out # 这里的'()'会导致报错'NoneType' object is not callable
# 只要去掉out后面的括号即可解决问题
def whatever():
pass
return whatever
@zhuang_shi_qi
def func1():
pass
@zhuang_shi_qi
def func2():
pass
if __name__ == '__main__':
func1() #如果前面加了括号,这里将会不可调用,虽然去掉这里的括号也可以,但与“装饰器不改变函数调用的方式”原则相违背。
func2()
成功实现该功能

在之前的这个小实验中,基本上了解了装饰器的用途和写法,然而不是所有的函数都向func1这样简单,无参数。
对于含不定参数的函数,参数由收集参数获取。
def zhuang_shi_qi(func):
def out(*args, **kwargs): # args为何物见http://t.csdn.cn/xfM7a
func(*args, **kwargs)
print(func.__name__)
return out
@zhuang_shi_qi
def func1(a, b):
print(a+b)
@zhuang_shi_qi
def func2(a, b, c):
print(a+b+c)
if __name__ == '__main__':
func1(1, 2)
func2(1, 2, 3)

不同的装饰器是可以给同一个函数装饰的,会从最后一个装饰器开始执行到第一个装饰器,再执行函数本身。