python装饰器的使用(详细解析)

什么是装饰器?

python装饰器(fuctional decorators)就是用于拓展原来函数功能的一种函数,目的是在不改变原函数名(或类名)的情况下,给函数增加新的功能。

这个函数的特殊之处在于它的返回值也是一个函数,这个函数是内嵌“原“”函数的函数。
你新买的毛坯房,装修后变好看了(装修、家具就是新的特效)
孙悟空被放进炼丹炉装饰了一下,出来后,学会了火眼金睛,以前的本领都还在

为什么用装饰器?

因为引入装饰器会便于开发,便于代码复用。
比如有一个函数A,需要添加新的功能,如果你修改原函数A的话会对其它已经引用该函数的地方产生影响,为了避免这样情况,使用装饰器来添加新的功能。
概括的讲,装饰器的作用就是为已经存在的函数或对象添加额外的功能。
装饰器实际上就是对函数进行了包装,它能够在不改变函数的前提下,在这个函数被执行之前或者执行之后执行一段代码.

如何使用装饰器?

工作原理:

假设用 funA() 函数装饰器去装饰 funB() 函数,如下所示:
funA 作为装饰器函数

def funA(fn):
    fn() # 执行传入的fn参数
    return '...'
@funA
def funB():

实际上,上面程序完全等价于下面的程序:
def funA(fn):
fn() # 执行传入的fn参数
return '...'
def funB():
funB = funA(funB)
通过比对以上 2 段程序不难发现,使用函数装饰器 A() 去装饰另一个函数 B(),其底层执行了如下 2 步操作:
将 B 作为参数传给 A() 函数;
将 A() 函数执行完成的返回值反馈回 B。

显然,被“@函数”修饰的函数不再是原来的函数,而是被替换成一个新的东西(取决于装饰器的返回值),即如果装饰器函数的返回值为普通变量,那么被修饰的函数名就变成了变量名;同样,如果装饰器返回的是一个函数的名称,那么被修饰的函数名依然表示一个函数。
实际上,所谓函数装饰器,就是通过装饰器函数,在不修改原函数的前提下,来对函数的功能进行合理的扩充。

带参数的函数装饰器

如果被修饰的函数本身带有参数,那应该如何传值呢?
最简单的解决方式是用 *args 和 *kwargs 作为装饰器内部嵌套函数的参数,args 和 **kwargs 表示接受任意数量和类型的参数。举个例子:

def funA(fn):
    # 定义一个嵌套函数
    def say(*args,**kwargs):
        fn(*args,**kwargs)
    return say
@funA
def funB(arc):
    print("C语言中文网:",arc)
@funA
def other_funB(name,arc):
    print(name,arc)
funB("http://c.biancheng.net")
other_funB("Python教程:","http://c.biancheng.net/python")

运行结果为:
C语言中文网: http://c.biancheng.net
Python教程: http://c.biancheng.net/python
函数装饰器可以嵌套
上面示例中,都是使用一个装饰器的情况,但实际上,Python 也支持多个装饰器,比如:
@funA
@funB
@funC
def fun():
上面程序的执行顺序是里到外,所以它等效于下面这行代码:
fun = funA( funB ( funC (fun) ) )

def timer(func): """计算一个函数执行的时间""" print("func is %s" ,func) def inner(*args,**kwargs): start = time.time() ret = func(*args,**kwargs) print(time.time()-start) return ret print("inner is %s" ,inner) return inner @timer # ---> func1 = timer(func1) def func1(a): time.sleep(2) print(a) @timer def func2(a,b): time.sleep(2) print(a,b) @timer def func3(): time.sleep(2) print("Hello World!") func1(1) # func2(1,2) #func3()

执行顺序:
1.先执行timer,申请一块内存地址,相当于门牌号
2.在执行inner,申请一块内存地址
3.把inner函数名传递给func1,func1指向inner函数的内存地址
4.此时执行funct1,也就是执行inner函数