函数 (三) 装饰器

时间:2022-05-08
本文章向大家介绍函数 (三) 装饰器,主要内容包括一 为何要用装饰器、二 什么是装饰器、三 装饰器的使用、四、装饰器语法及固定格式、五、应用练习、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

一 为何要用装饰器

有的时候写完一段代码,过段时间需要对它进行升级、添加一些新功能,但是如果要直接修改原来的代码会影响其他人的调用,所以就需要一个不修改源代码且不修改原函数的调用方式的东西又能为原函数增添新功能的东西,装饰器就是干这个的。

二 什么是装饰器

装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式
装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能

三 装饰器的使用

下面是为一个函数添加装饰器,添加了计算其运行时间的功能:

 1 import time
 2 def timmer(func):
 3     def wrapper(*args,**kwargs):
 4         start_time=time.time()
 5         res=func(*args,**kwargs)
 6         stop_time=time.time()
 7         print('run time is %s' %(stop_time-start_time))
 8         return res
 9     return wrapper
10 
11 @timmer
12 def foo():
13     time.sleep(3)
14     print('from foo')
15 foo()

四、装饰器语法及固定格式

1 def 装饰器函数名(func):
2     def wrapper(*args,**kwargs):    
3         ret = func(*args,**kwargs)
4         return ret
5     return wrapper
6 
7 @装饰器函数名
8 def func():
9    pass

五、应用练习

 1 #######################################作业练习#######################################################
 2 #
 3 # 1.编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
 4 # user_exist = [False]
 5 # def auth(func):
 6 #     def wrapper(*args,**kwargs):
 7 #         #注册功能
 8 #         with open('db.txt','r',encoding='utf-8') as f:
 9 #             user_dic = eval(f.read())
10 #             flag = False
11 #         while not user_exist[0]:
12 #             username = input('请输入您的用户名:').strip()
13 #             password = input('请输入您的密码:').strip()
14 #             if username in user_dic and password == user_dic[username]:
15 #                 print('恭喜您,登录成功!')
16 #                 user_exist[0] = True
17 #                 break
18 #             else:
19 #                 print('账号或密码错误,请重新输入!')
20 #         ret = func(*args,**kwargs)
21 #         return ret
22 #     return wrapper
23 #
24 # @auth
25 # def func1():
26 #     print('函数1')
27 # @auth
28 # def func2(x):
29 #     print('函数2',x)
30 # func1()
31 # func2(111111)
32 # 2.编写装饰器,为多个函数加上记录调用功能,要求每次调用函数都将被调用的函数名称写入文件
33 # def log(func):
34 #     def wrapper(*args,**kwargs):
35 #         with open('db2.txt','a',encoding='utf-8') as f:
36 #             f.write('%s函数正在被调用。n'%func.__name__)
37 #         ret = func(*args,**kwargs)
38 #         return ret
39 #     return wrapper
40 # @log
41 # def func1():
42 #     print('func1函数被调用了。。。。')
43 # @log
44 # def func2():
45 #     print('func2函数被调用了。。。。')
46 #
47 # func1()
48 # func2()
49 # 进阶作业(选做):
50 # 1.编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
51 from urllib.request import urlopen
52 
53 # def get_html(url):
54 #     print(urlopen(url).read())
55 #
56 # get_html('http://www.baidu.com')
57 # 2.为题目1编写装饰器,实现缓存网页内容的功能:
58 # 具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则,就去下载,然后存到文件中
59 # from urllib.request import urlopen
60 # 
61 # def get_bak(func):
62 #     def wrapper(*args,**kwargs):
63 #         with open('html.bak','r+',encoding='utf-8') as f:
64 #             if not f.read():
65 #                 ret = func(*args, **kwargs)
66 #                 print(ret)
67 #                 f.write(ret.decode('utf-8'))
68 #             else:
69 #                 print('以下内容是从缓存中获得的^^^^^')
70 #                 f.seek(0)
71 #                 print(f.read())
72 #         ret = func(*args, **kwargs)
73 #         return ret
74 #     return wrapper
75 # 
76 # @get_bak
77 # def get_html(url):
78 #     return urlopen(url).read()
79 # get_html('http://www.python.org')