看完廖雪峰的python教程中的装饰器部分,对装饰器深有体会了。
装饰器(Decorator),他确实是起装饰作用的,而且是装饰函数的(好像也可以装饰类,不过还没学,见谅),不过不是让函数看起来更加好看的,而是对函数添加一些额外功能的,这也是一种装饰。
先来看一段代码:
In [152]: def log(func):
...: def wrapper(*args, **kwargs):
...: print("call {}()".format(func.__name__))
...: return func(*args, **kwargs)
...: return wrapper
...:
...:
这里的log函数就是一个装饰器,它接受一个函数作为参数,同时返回一个wrapper函数。
但是其实内部的wrapper函数才是真正起修饰功能的部分,它可以接受任意参数,因此也当wrapper函数被返回后被重新调用时可以接受func函数的所有需要的参数。
warpper函数中的参数就是传递给func函数用的,但是wrapper函数不知道func函数需要什么参数,因此接受任意参数。
在wrapper函数内部,print语句这一行,就相当于对func函数添加的额外功能,但是又没有改变func函数的内部结构,只是在外部改变的;return这一行,执行了真正的func的功能,并且返回了执行后的值。这也让wrapper函数在后面的重新调用中真正模拟了func的作用(执行同样的功能,有同样的返回值),但是添加了额外的功能。
在python中使用@语法,可以间装饰器放在函数定义的前面。如下:
In [153]: @log
...: def multi(n):#计算从1到n的累乘(阶乘)
...: return functools.reduce(lambda x,y:x*y, range(1,abs(n)))
...:
...:
在函数定义前面加上 @log 相当于:
multi = log(multi)
log是一个Decorator,它接受一个函数,同时也返回一个函数。
这里相当于使用一个同名变量multi指向了新函数,原来的multi函数还在。
因此在我们执行multi(n)时,已经不是原来的multi函数了(其实是装饰器内部的wrapper函数,这个multi中的n就是传递给原来multi函数中的n),但是和原来的函数拥有相同的功能,而且多了额外的功能(print了一下...)
In [154]: result = multi(10)
call multi()
In [155]: result
Out[155]: 362880