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()

执行顺序

 



posted @ 2018-07-19 21:52  前往Python取经之路  阅读(179)  评论(0编辑  收藏  举报