python 基础---装饰器
装饰器的本质:一个闭包函数
装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展
装饰器的返回值:也是一个函数
1 import time
2
3 def func1():
4 print('in func1')
5
6 def timer(func):
7 def inner():
8 start = time.time()
9 func()
10 print(time.time() - start)
11 return inner
12
13 func1 = timer(func1)
14 func1()
语法糖
1 import time
2 def timer(func):
3 def inner():
4 start = time.time()
5 func()
6 print(time.time() - start)
7 return inner
8
9 @timer #==> func1 = timer(func1)
10 def func1():
11 print('in func1')
12
13
14 func1()
内包有参数
1 import time
2 def timer(func):
3 def inner(*args,**kwargs):
4 start = time.time()
5 re = func(*args,**kwargs)
6 print(time.time() - start)
7 return re
8 return inner
9
10 @timer #==> func1 = timer(func1)
11 def func1(a,b):
12 print('in func1')
13
14 @timer #==> func2 = timer(func2)
15 def func2(a):
16 print('in func2 and get a:%s'%(a))
17 return 'fun2 over'
18
19 func1('aaaaaa','bbbbbb')
20 print(func2('aaaaaa'))
装饰器的固定格式
1 def timer(func):
2 def inner(*args,**kwargs):
3 '''执行函数之前要做的'''
4 re = func(*args,**kwargs)
5 '''执行函数之后要做的'''
6 return re
7 return inner
1 from functools import wraps
2
3 def deco(func):
4 @wraps(func) #加在最内层函数正上方
5 def wrapper(*args,**kwargs):
6 return func(*args,**kwargs)
7 return wrapper
默写装饰器
1 装饰器默写
2 def wapper(f): # f = func5
3 def inner(*args,**kwargs):
4 print("装饰器开始")
5 ret = f(*args,**kwargs) #执行 func5(*args,**kwargs),func5(5,10)
6 print("装饰器结束")
7 return ret
8 return inner
9
10 @wapper #func5 = wapper(func5) func5 = inner
11 def func5(a,b):
12 print('本程序')
13 print(a+b)
14 return (a*b)
15
16 ret = func5(5,10) #执行func5(5,10)相当于执行inner(5,10)
17 print(ret)
__doc__
__name__
1 #再次默写装饰器函数 2 def wrapper(f): 3 def inner(*args,**kwargs): 4 pass #在装饰之前要做的事情 5 print('在装饰之前要做的事情') 6 ret = f(*args,**kwargs) 7 pass #在装饰之后要做的事情 8 print('在装饰之后要做的事情') 9 return ret 10 return inner 11 12 @wrapper #func = wrapper(func) 13 def func(day): 14 ''' 15 我只是一个函数说明 16 :param day: 17 :return: 18 ''' 19 print('我是要被装饰的函数,你能拿我咋的') 20 print('全体放假%s天'%day) 21 #print('全体放假{}天'.format(day)) 22 return '好开心' 23 24 ret = func(4) 25 print(ret) 26 27 print(func.__doc__) #查看函数的说明
28 print(func.__name__) #查看函数名
输出结果:
在装饰之前要做的事情
我是要被装饰的函数,你能拿我咋的
全体放假4天
在装饰之后要做的事情
好开心
None
inner
wraps:使用 .__name__和 .__doc__
1 from functools import wraps
2 def wrapper(f):
3 @wraps(f)
4 def inner(*args,**kwargs):
5 pass #在装饰之前要做的事情
6 print('在装饰之前要做的事情')
7 ret = f(*args,**kwargs)
8 pass #在装饰之后要做的事情
9 print('在装饰之后要做的事情')
10 return ret
11 return inner
12
13 @wrapper #func = wrapper(func)
14 def func(day):
15 '''
16 这是一个放假通知
17 :param day:
18 :return:
19 '''
20 print('我是要被装饰的函数,你能拿我咋的')
21 print('全体放假%s天'%day)
22 #print('全体放假{}天'.format(day))
23 return '好开心'
24
25 ret = func(4)
26 print(ret)
27
28 print(func.__name__)
29 print(func.__doc__)
输出结果:
在装饰之前要做的事情
我是要被装饰的函数,你能拿我咋的
全体放假4天
在装饰之后要做的事情
好开心
func
这是一个放假通知
:param day:
:return:
题目1:
编写装饰器,为多个函数加上认证的功能
(用户登陆成功一次,后续的函数都无需再输入用户名和密码)
1 FLAG = False #做标签
2 def login(func):
3 def inner(*args,**kwargs):
4 global FLAG #全局变量
5 '''登陆程序'''
6 if FLAG:
7 ret = func(*args, **kwargs) # 被装饰
8 return ret
9 else:
10 username = input('username:')
11 passwd = input('passwd:')
12 if username =='boss_gold' and passwd == '222222':
13 FLAG = True
14 ret = func(*args,**kwargs)#被装饰
15 return ret
16 else:
17 print('登陆失败')
18 return inner
19
20 @login
21 def shoplist_add():
22 print('增加一件物品')
23
24 @login
25 def shoplist_del():
26 print('删除一件物品')
27
28 shoplist_add()
29 shoplist_del()
输出结果:
username:boss_gold
passwd:222222
增加一件物品
删除一件物品
题目2:
编写装饰器,为多个函数加上记录调用功能,要求每次调用函数都将被调用的函数名称写入文件
1 def log(func):
2 def inner(*args,**kwargs):
3 with open('log','a+',encoding='utf-8')as f:
4 # for line in f:
5 # print(line)
6 # print('来了吗')
7 # if line=='shoplist_add':
8 # pass
9 # else:
10 f.write(func.__name__+'\n')
11 #在装饰器函数之前所做的事情
12 ret = func(*args,**kwargs)
13 #在装饰器函数之后所做的事情
14 return ret
15 return inner
16
17 @log
18 def shoplist_add():
19 print('增加一件物品')
20
21 @log
22 def shoplist_del():
23 print('删除一件物品')
24
25 shoplist_del()
26 shoplist_add()
输出结果:
删除一件物品
增加一件物品
log文件内容:
shoplist_del
shoplist_add
题目3:
进阶作业
1.编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
1 from urllib.request import urlopen 2 def get(url): 3 code = urlopen(url).read 4 return code 5 ret = get('http://www.baidu.com') 6 print(ret)
结果:
返回网页下载结果
2.为题目1编写装饰器,实现缓存网页内容的功能:
具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),
就优先从文件中读取网页内容,否则,就去下载,然后存到文件中
1 import os 2 from urllib.request import urlopen 3 def cache(func): 4 def inner(*args,**kwargs): 5 if os.path.getsize('web_cache'): #判断文件中是否有内容,返回的文件大小,没文件就是0 = False,第一次就是0 6 with open('web_cache','rb')as f: 7 return f.read() #如果有内容,直接return返回,不执行下面的操作 8 ret = func(*args,**kwargs) #这里执行的get() 请求网页,ret就是网页的内容 9 with open('web_cache','wb')as f: #将请求的结果写到文件里 10 f.write(b'*********'+ret) # b'*********'标识符,看是文件里面的还是网页下载的 11 return ret 12 return inner 13 14 @cache #相当于get = cache(get) 15 def get(url): 16 code = urlopen(url).read() 17 return code 18 19 ret = get('http://www.baidu.com') 20 print(ret) 21 ret = get('http://www.baidu.com') 22 print(ret) 23 ret = get('http://www.baidu.com') 24 print(ret)
结果:
第一次输出是不带*********的,也就是网页下载的
第二次和第三次是带*********的,是从文件里面读取的
多个函数需要装饰
给函数计算时间的装饰器
带参数的装饰器:三层
1 import time
2 FLAGE = True
3 #FLAGE = False
4 def timmer_out(FLAGE):
5 def timmer(func):
6 def inner(*args,**kwargs):
7 if FLAGE:
8 start = time.time()
9 ret = func(*args,**kwargs)
10 end = time.time()
11 print(end - start)
12 return ret
13 else:
14 ret = func(*args, **kwargs)
15 return ret
16 return inner
17 return timmer
18
19 @timmer_out(FLAGE) # timmer_out(FLAGE) = timmer @timmer :wahaha = timmer(wahaha)
20 def wahaha():
21 time.sleep(0.1)
22 print('wahahahaha')
23
24 @timmer_out(FLAGE)
25 def erguotou():
26 time.sleep(0.2)
27 print('erguotoutoutoutou')
28
29 wahaha()
30 erguotou()
多个装饰器装饰一个函数
1 def wrapper1(func): #func = f
2 def inner1():
3 print('wrapper1 ,before func')
4 ret = func() #f()
5 print('wrapper1 ,after func')
6 return ret
7 return inner1
8
9 def wrapper2(func): #func = inner1
10 def inner2():
11 print('wrapper2 ,before func')
12 ret = func() #inner1()
13 print('wrapper2 ,after func')
14 return ret
15 return inner2
16
17 @wrapper2 # f = wrapper2(f) :f = wrapper2(inner1) f = inner2
18 @wrapper1 # f = wrapper1(f) :f = inner1
19 def f():
20 print('in f')
21
22 f() # inner2()
执行顺序