一 概述
装饰器:本质是函数
功能:用来装饰其他函数,为其他函数添加附加功能
二 装饰器原则
不能修改被装饰函数的源代码
不能修改被装饰函数的调用方式
三 实现装饰器的知识储备
函数即“变量”
高阶函数
嵌套函数
最终:高阶函数+嵌套函数 =》 装饰器
1. 高阶函数
实现高阶函数的两个条件:
把一个函数名当作实参传给另一个函数
返回值中包含函数名
条件1作用:在不修改被装饰函数源代码的情况下为其添加功能
import time
def bar():
time.sleep(1)
print("in the bar")
def test(func):
print(func)
start_time = time.time()
func()
stop_time = time.time()
print("the func run the is %s " % (stop_time-start_time))
#没有修改bar的源代码
test(bar) #把bar函数名当作实参传到test中
#输出
<function bar at 0x033AD6A8>
in the bar
the func run the is 1.0007984638214111
没有修改bar函数的源代码,但是调用方式改变了
条件2作用:不修改函数的调用方式
import time
def bar():
time.sleep(1)
print("in the bar")
def test(func):
print(func)
start_time = time.time()
func()
stop_time = time.time()
print("the func run the is %s " % (stop_time-start_time))
return func #返回函数内存地址
bar = test(bar)
bar() #没有改变bar函数调用方式
#输出
<function bar at 0x027FD6A8>
in the bar
the func run the is 0.0
in the bar
没有修改bar函数的调用方式和源代码,但是输出结果改变了
2. 嵌套函数
定义:在一个函数的函数体内,用def 去声明一个函数,而不是去调用其他函数,称为嵌套函数
def foo():
print("in the foo")
def bar():
print("in the bar")
bar()
foo()
#输出
in the foo
in the bar
四 装饰器定义
1. 定义
装饰器实现的条件:高阶函数+嵌套函数 =》装饰器
import time
#定义装饰器
def timmer(func):
def deco():
stat_time = time.time()
func()
stop_time = time.time()
print("the func run time is %s" % (stop_time-stat_time))
return deco
#装饰test函数
@timmer #@timmer相当于test = timmer(test)
def test():
time.sleep(1)
print("in the test")
test()
#输出
in the test
the func run time is 1.0006682872772217
执行步骤:
1.执行timmer函数,timmer(test)返回值赋值给test变量,即test = timmer(test)
2.此时的test的值是执行timmer函数返回值deco,即test = deco
3. 所以执行test,其实就是执行的是deco函数,test()就是执行deco函数
2. 执行函数带参数
import time
#定义装饰器
def timmer(func):
def deco(*args,**kwargs): #传入非固定参数
stat_time = time.time()
func(*args,**kwargs) #传入非固定参数
stop_time = time.time()
print("the func run time is %s" % (stop_time-stat_time))
return deco
#装饰test函数
@timmer #@timmer相当于test = timmer(test)
def test(name,age): #带参数
time.sleep(1)
print("name: %s, age:%d" % (name,age))
@timmer
def test1(): #不带参数
time.sleep(1)
print("in the test1")
test("alex",22)
test1()
#输出
name: alex, age:22
the func run time is 1.0008456707000732
in the test1
the func run time is 1.0008673667907715
3.执行函数有返回值
def timmer(func): #func = test
def deco(*args,**kwargs):
res = func(*args,**kwargs) #函数执行结果返回值赋给res
return res #返回res
return deco
@timmer
def test():
print("in the test")
return "from the test" #执行函数rest有返回值
res = test()
print(res)
#输出
in the test
from the test
4. 装饰器带参数
之前我们的装饰器都是没有带参数的,其实我们已经能解决90%的问题了,但是如果说有一种情况:就是在你访问不同页面时,你用的验证的方式来源不同,这时就要用到带参数的装饰器了。
user,passwd = "alex","abc123"
def auth(auth_type): #传递装饰器的参数
print("auth func:",auth_type)
def out_wrapper(func): #将被装饰的函数当作实参传递进来
def wrapper(*args,**kwargs): #将被装饰的函数的参数传递进来
#print("wrapper func args:",*args,**kwargs)
username = input("username:").strip()
password = input("password:").strip()
if auth_type == "local":
if user == username and passwd == password:
print("\033[31;1mUser has passed authentication\033[0m")
res = func(*args,**kwargs)
return res
else:
exit("Invalid username or password")
elif auth_type == "ldap":
pass
return wrapper
return out_wrapper
def index():
print("welcome to index page")
@auth(auth_type="local") #带参数装饰器
def home():
print("welcome to home page")
return "from home"
@auth(auth_type="ldap") #带参数装饰器
def bbs():
print("welcome to bbs page")
index()
print(home())
bbs()
从上面的例子可以看出,执行步骤:
1. out_wrapper = auth(auth_type="local")
2. home = out_wrapper(home)
3. home()
所以这个函数的作用分别是:
1. auth(auth_type) 传递装饰器参数
2. out_wrapper(func) 把函数当作实参传递进来
3. wrapper(*args,**kwargs) 真正执行装饰的函数