其实python中的装饰器可以简化成下面的格式
import time import random def timmer(func): def inner(): start_time=time.time() func() end_time=time.time() print("run time: %s " %(end_time-start_time)) return inner @timmer def index(): time.sleep(random.randrange(1,5)) print("welcome to index page") @timmer def home(): time.sleep(random.randrange(1,5)) print("welcome to home page") index() home()程序执行结果
welcome to index page run time: 2.0 welcome to home page run time: 4.0可以看出,使用@加装饰器名添加到被装饰对象的上方的方式也可以为一个函数添加装饰器中定义的功能
6.多个装饰器的定义与调用在上面的例子里,定义并调用了一个统计程序运行时间的装饰器timmer,
如果现在想为index函数添加一个用户认证的功能,可以定义一个名为auth的装饰器
import time import random def auth(func): def wrapper(): while True: user=input("Input your username>>>:").strip() pwd=input("Input your password>>>:").strip() if user== "abcd" and pwd == "abcd1234": print("login successful") func() break else: print("login error") return wrapper @auth def index(): time.sleep(random.randrange(1,5)) print("welcome to index page") index()运行程序
Input your username>>>:abcd # 先输入错误的用户名和密码 Input your password>>>:1234 login error # 提示用户输入错误,登录失败 Input your username>>>:abcd # 让用户再次输入用户名和密码 Input your password>>>:abcd1234 login successful # 登录成功 welcome to index page # 执行index函数从程序执行结果可以看出,用户登录密码验证的装饰器auth已经定义并被成功调用了
如果想为index函数添加用户认证的功能,又想统计index函数执行时间的功能,在使用装饰器的情况下该怎么调用呢
import time import random def timmer(func): def inner(): start_time=time.time() func() end_time=time.time() print("run time: %s " %(end_time-start_time)) return inner def auth(func): def wrapper(): while True: user=input("Input your username>>>:").strip() pwd=input("Input your password>>>:").strip() if user== "abcd" and pwd == "abcd1234": print("login successful") func() break else: print("login error") return wrapper @timmer @auth def index(): time.sleep(2) print("welcome to index page") index()在上面的代码里,为index函数添加了两个装饰器,现在有一个问题,就是这两个装饰器究竟哪个先被调用,哪个后被调用呢??
来分析一下,
如果timmer装饰器先被调用,那么程序就会先执行timmer装饰器,然后再执行auth装饰器,提示输入用户名和密码, 这样一来timmer装饰器统计的时间就会包括输入用户名和密码的时间,这个时间会远远大于index函数睡眠的2秒种; 如果auth装饰器先被调用,timmer装饰器后被调用,那么timmer装饰器统计的运行时间就应该只包括index函数的执行时间值应该在2秒多一点点的时间范围内运行程序,先输入错误的用户名和密码以使用程序的执行时间加长
Input your username>>>:abcd Input your password>>>:abcd login error Input your username>>>:abcd Input your password>>>:abcd1234 login successful welcome to index page run time: 12.759000062942505从程序的执行结果可以知道,程序是先运行timmer装饰器,然后才运行auth装饰器,所以timmer统计的时间就包括了用户认证的时间,所以timmer统计到的程序运行时间远远大于index睡眠的2秒钟
所以这里得出一个结论:
当一个函数同时被两个装饰器装饰时,加上函数最上面的装饰器先执行,加在下面的装饰器先装饰把上面例子里的timmer装饰器和auth装饰器位置互换一下
import time import random def timmer(func): def inner(): start_time=time.time() func() end_time=time.time() print("run time: %s " %(end_time-start_time)) return inner def auth(func): def wrapper(): while True: user=input("Input your username>>>:").strip() pwd=input("Input your password>>>:").strip() if user== "abcd" and pwd == "abcd1234": print("login successful") func() break else: print("login error") return wrapper @auth @timmer def index(): time.sleep(2) print("welcome to index page") index()运行index函数,依然先输入错误的用户名和密码,增加用户认证的时间
Input your username>>>:abcd Input your password>>>:abcd login error Input your username>>>:abcd Input your password>>>:abcd1234 login successful welcome to index page run time: 2.0可以看到,这次timmer统计到的时间只包含index函数的运行时间,不包含用户进行认证的时间