装饰器(学习路线)
1. 为什么使用装饰器?
2. 简单的装饰器实例
3. 多层装饰器的执行顺序是怎么样的?
4. 练习题
一、为什么使用装饰器?
https://www.zhihu.com/question/26930016 【知乎上的神仙回答的比较好玩,这里不做过多的赘述】
二、简单的装饰器实例
# -*- coding: utf-8 -*-
from time import time
import functools
from time import sleep
def add_log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
start_time = time()
f = func(*args, **kw)
end_time = time()
print('函数名:%s,运行时间:%.6f,运行返回值结果:%d' % (func.__name__, end_time - start_time, f))
return f
return wrapper
@add_log
def add(x, y):
sleep(1)
return x + y
if __name__ == '__main__':
print(add(1, 10))
"""
Q1: 为什么在装饰器函数print inner函数的时候使用的是func.name而不是f.name
A1: 因为这里f是函数的返回结果,结果对象没有对应的name属性
"""
三、多层装饰器的执行顺序是怎样的呢?
# -*- coding=utf-8 -*-
def dec1(func):
print('1111')
def one():
print('2222')
func()
print('3333')
return one
def dec2(func):
print('aaaa')
def two():
print('bbbb')
func()
print('cccc')
return two
@dec1
@dec2
def test():
print('test test')
test()
>>>>aaaa
>>>>1111
>>>>2222
>>>>bbbb
>>>>test test
>>>>cccc
>>>>3333
"""
有很多朋友应该和我一样在看到这个执行结果的时候有不理解的地方
那么我们一步一步的拆解来看
@dec1
@dec2
def test()
我们先将这个写成test = dec1(dec2(test)) >>这个过程是装饰过程
1. dec2(test) 输出aaaa 然后返回 two函数对象(注意:此时dec2中的func就变成了test函数)
2. dec1(two) 输出1111 然后返回one函数对象(注意:此时dec1中的func就变成了two函数)
3. test = dec1(dec2(test)) 其实就变成了test = one 这个时候先执行one函数 输出2222
4. 执行one函数中的func(重点来了:one函数里面的func函数第2步骤的时候变成了two函数 所以这个时候执行的是 two函数)输出bbbb
5. 执行two函数中的func函数(重点又来了:two函数中的func函数在装饰的时候变成了test函数 所以这个时候执行的是我们真正的业务函数test) 输出test test
6. 此时还是在two函数中执行完了被test函数替代的func之后 后边的代码是输出cccc
7. 这个时候one函数中的two函数(func)彻底执行完毕,然后执行one函数中func后边的执行语句输出3333
"""
四、 练习题:(在练习中找问题)
# -*- coding: utf-8 -*-
import functools
import time
"""
练习题:
登录5分钟之后需要重新登录
5分钟之后可以shoplist_add and shoplist_del
"""
login_time = 0
def login_time_verify(func):
@functools.wraps(func)
def wrapper(*args, **kw):
global login_time
if (time.time() - login_time)/300.00 < 1:
res = func(*args, **kw)
return res
else:
username = raw_input('亲输入你的名字:')
password = raw_input('亲输入你的密码:')
if username == 'rxx' and password == '123':
login_time = time.time()
res = func(*args, **kw)
return res
else:
print('login fail')
return wrapper
@login_time_verify
def shoplist_add():
print('增加一件物品')
@login_time_verify
def shoplist_del():
print('删除一件物品')
if __name__ == '__main__':
shoplist_add()
shoplist_del()
time.sleep(200)
shoplist_add()
shoplist_del()
time.sleep(101)
shoplist_add()
shoplist_del()
# -*- coding=utf-8 -*-
from functools import wraps
import logging
"""
写一个日志函数,并且这个日志函数有接收参数
"""
def use_logging(level):
def decorator(func):
@wraps(func)
def wrapper(*args,**kw):
if level == 'warn':
# logging.warn('%s is running' %func.__name__)
# 这里有个问题 为什么logging会在被装饰的函数print之后才输出,暂时不知道,希望有懂的小伙伴帮忙解答一下(下边这个print不存在的情况下warn 会在被装饰函数输出之后输出)
print('%s is running' %func.__name__)
return func(*args,**kw)
return wrapper
return decorator
@use_logging(level = 'warn')
def foo(name):
print('im is %s' %name)
@use_logging(level='info')
def loo(name):
print('im is %s' %name)
if __name__ == '__main__':
foo('foo')
loo('i love you')