函数装饰器

对于某个函数,如果希望在不改变函数代码的前提下,为该函数增加额外的功能,
那么可以使用装饰器来装饰该函数。

装饰器是一个函数,装饰器接收一个函数作为参数(传入的实参是被装饰的函数),
装饰器的内部嵌套定义另一个函数,内函数中会引用装饰器的参数,并且装饰器的返回值是内函数。
这样构成了一个闭包。

为了让内函数接收任意类型的参数,将内函数的形参定义为(*args, **kwargs)。
在函数中首选完成为被装饰函数添加新功能,然后调用被装饰的函数。

装饰器的应用语法:
在被装饰函数的前面添加:"@装饰器的函数名"。

●为add函数添加log功能。

#执行流程:
1,被装饰的函数add作为实参传递给装饰器log。
2,返回装饰器的内函数wrapper。
3,将内函数wrapper赋值给名为add(被装饰函数的函数名)的变量。
4,再调用被装饰函数add时,其实调用的是装饰器的内函数wrapper。

 1 #add函数的装饰器函数。
 2 def log(func):
 3     def wrapper(*args, **kwargs):
 4         print("函数%s被调用了" % func.__name__)
 5         return func(*args, **kwargs)
 6     return wrapper
 7 
 8 #添加标记@log,对函数add应用装饰器。相当于调用了add = log(add)
 9 @log  
10 def add(sum1, sum2):
11     print(sum1, sum2)
12     return sum1 + sum2
13 
14 #调用方法和通常一样。打印调用结果。
15 print(add(1, 2))
16 
17 #打印实际被调用的函数名。
18 print(add.__name__) #结果为wrapper。

●实现被装饰后,函数名依旧是add。

在装饰器的内函数前面添加另外一个装饰器:@functools.wraps(装饰器的函数名),
functools.wraps为标准库模块functools中的函数wraps。

 1 import functools
 2 
 3 def log2(func):
 4     @functools.wraps(func)
 5     def wrapper(*args, **kwargs):
 6         print("函数%s被调用了" % func.__name__)
 7         return func(*args, **kwargs)
 8     return wrapper
 9 
10 @log2
11 def add2(sum1, sum2):
12     print(sum1, sum2)
13     return sum1 + sum2
14 
15 print(add2(1, 2))
16 
17 print(add2.__name__) #结果为add2。

●给装饰器传递额外参数。
需要3层嵌套装饰器。
对于@log3('6月','18日'),相当于执行语句:add3 = log3('6月','18日')(add3)。

 1 def log3(month, day):
 2     def decorator(func):
 3         @functools.wraps(func)
 4         def wrapper(*args, **kwargs):
 5             print("%s%s, 函数%s被调用了" % (month, day, func.__name__))
 6             return func(*args, **kwargs)
 7         return wrapper
 8     return decorator
 9 
10 @log3('6月', '18日')
11 def add3(sum1, sum2):
12     print(sum1, sum2)
13     return sum1 + sum2
14 
15 print(add3(1, 2))
原文地址:https://www.cnblogs.com/mountain2011/p/10988961.html