装饰器的原则:
开放封闭原则:对扩展是开放的,对修改是封闭的;
装饰器的作用:
在不改变原函数调用的情况下,扩展被装饰函数的功能(可以在装饰器函数内部,在被装饰函数的前后分别添加相应的功能);
装饰器函数的本质:
装饰器函数本质上就是一个闭包函数;
装饰器函数固定模式:
def wrapper(f): #装饰器函数 def inner(*args): print("在被装饰的函数之前添加的功能") #1最先被打印 ret=f(*args) #被装饰的函数func带有返回值 print("在被装饰的函数之后添加的功能") #3 被打印 return ret return inner @wrapper def func(a,b,c): #被装饰的函数 print(a,b,c) #2.执行被装饰的函数时被打印 return "哈哈哈哈" #4.最后返回的结果在全局中被打印 ret=func(1,2,3) print(ret)
wraps
先介绍一个函数的功能,就是可以以一个字符串的形式返回一个函数的函数名 func.__name__ ;
可以返回函数的注释信息,就是写在函数内部功能之前 最开始的注释 func.__doc__;
def func(): '''我是一个func函数''' print('hello') print(func.__name__,type(func.__name__)) #以字符串的形式返回函数的名 print(func.__doc__) #返回一个函数内部注释
运行结果:
现在我们来看装饰器固定模式这个代码,有一个很有意思的事:
def wrapper(f): #装饰器函数 def inner(*args): print("在被装饰的函数之前执行的代码") ret=f() print("在被装饰的函数之后执行的代码") return ret return inner #wrapper()函数有返回值 @wrapper def func(a,b,c): print(a,b,c) return "哈哈哈哈" print(func.__name__)
运行结果:
我们打印func()函数的名字(使用func.__name__ 以字符串的形式打印函数名)发现竟然是inner!
原因是,我们在被装饰的函数func 定义上方写了@wrapper,相当于在函数定义结束后写了 func=wrapper(func) 其实你会发现,我们之前跟wrapper()函数同一级别定义的func()函数已经以一个参数的形式传给了f
,然后wrapper()函数的返回值inner(其实也是一个函数,只不过在wrapper()函数内部的一个闭包函数)我们给了变量func,所以这里的func 不再是原来在全局空间定义的函数了,而是一个inner函数名,那我们怎么才可以跟之前一样,func.__name__时打印出func的函数名呢,也就是调用func()时在扩充了功能的前提下,就跟真实的调用原来定义的那个函数一样呢?
我们可以这样操作:
from functools import wraps def wrapper(f): @wraps(f) def inner(*args): print("在被装饰的函数之前执行的代码") ret=f(*args) print("在被装饰的函数之后执行的代码") return ret return inner @wrapper def func(a,b): print(a,b) return "哈哈哈哈" print(func.__name__) print(func(1,2))
也就是from functools import wraps导入wraps ,然后在装饰器函数的内部,inner()闭包函数的上方加上 @wraps(f)即可;