Python之路,Day8 = Python基础8
装饰器
from functools imoort wraps # 保留原函数所有信息,比如:用__doc__查看注释的时候,显示原来的注释
def func01(func):
@wraps(func) # 用__doc__查看注释的时候,显示原来的注释
def wrapper(*args, **kwargs):
print('func01---------------------01')
res = func(*args, **kwargs)
print('func01---------------------02')
return res
# 上面的效果就相当于在这里加了一句 wrapper.__doc__ = func.__doc__
return wrapper
装饰器的参数:
再包一层
def doco(file_type = 'file'): def outer(func): def wrapper(*args, **kwargs): if file_type == 'file': print('with open file') elif file_type == 'mysql': print('deal with mysql') else: print('i do not konw how to deal') res = func(*args, **kwargs) return res return wrapper return outer @doco('file') def func1(): print('fucn1') @doco('mysql') def func2(): print('fucn2') @doco('abc') def func3(): print('fucn3') func1() func2() func3()
迭代器
1.重复
2.基于上一次的结果
可迭代对象:
python为了提供一种不依赖于索引的迭代方式,
会为一些对象内置 __iter__ 方法,
obj.__iter__称为可迭代的对象
obj.__iter__() 得到的结果就是迭代器
得到的迭代器,既有__iter__又有__next__方法
__iter__:
__next__: 返回下一个值
好处:
1.可以不依赖索引
2.惰性计算,节省内存
缺点:
1.取值麻烦,需要一个一个取值
2.不能往回取值
3.不能获取迭代器的长度
========================homework================
# 整理今天装饰器代码(每人手写一份,注意,是手写,交到小组长手里,明天我检查),准备明天默写
def demeo(file_type = 'file'): def outer(func): def inner(*args, **kwargs): if file_type == 'file': print('deal with 33[35;0mfile 33[0m...') elif file_type == 'mysql': print('deal with 33[35;0mmysql 33[0m...') else: print("deal with 33[35;0mothers 33[0m...") res = func(*args, **kwargs) return res return inner return outer @demeo() def f1(): print("my name is f1...") @demeo('mysql') def f2(): print('f2 is my name...') @demeo('abc') def f3(): print('is me, f3...') f1() f2() f3()
# 2 编写日志装饰器,实现功能如:一旦函数f1执行,则将消息2017-07-21 11:12:11 f1 run写入到文件中
# 注意:时间格式的获取
# import time
# time.strftime('%Y-%m-%d %X')
import time log_path = r'C:UsersAdministratorPycharmProjects老男孩全栈5期homeworkday08loglog.log' def outer(func): def inner(*args, **kwargs): with open(log_path, 'a', encoding='utf-8') as f: log_info = time.strftime('%Y-%m-%d %X ') + func.__name__ + ' run ' f.write(log_info) res = func() return res return inner @outer def f1(): print("This is f1.....") f1()
# 3 判断下列数据类型是可迭代对象or迭代器
#
# s='hello'
# l=[1,2,3,4]
# t=(1,2,3)
# d={'a':1}
# set={1,2,3}
# f=open('a.txt')
#
# 4 分别用依赖索引和不依赖索引两种方式迭代上述对象
from collections import Iterable s='hello' l=[1,2,3,4] t=(1,2,3) d={'a':1} set={1,2,3} f=open('a.txt') def print_while(a): count = 0 while count < len(a): print(a[count]) count += 1 def print_for(a): for i in a: if isinstance(a, dict): print(i,a[i]) else: print(i) print(' s is Iterable: %s'%isinstance(s, Iterable)) print_while(s) print_for(s) print(' l is Iterable: %s'%isinstance(l, Iterable)) print_while(l) print_for(l) print(' t is Iterable: %s'%isinstance(t, Iterable)) print_while(t) print_for(t) print(' d is Iterable: %s'%isinstance(d, Iterable)) # print_while(d) print_for(d) print('set is Iterable: %s'%isinstance(set, Iterable)) # print_while(set) print_for(set) print(' f is Iterable: %s'%isinstance(f, Iterable)) # print_while(f) print_for(f)
# 5 选做题:
# 基于课上所讲网页缓存装饰器的基础上,实现缓存不同网页的功能
# 要求,用户提交的不同url,都能缓存下来,对相同的url发起下载请求,优先从缓存里取内容
import os, time, hashlib # # print(hash('abcdefg')) # print(hash('abcdefg')) cach_dir = "C:\Users\Administrator\PycharmProjects\老男孩全栈5期\homework\day08\cach\" # 设置一个缓存的目录 print(cach_dir) if not os.path.exists(cach_dir): # 查看缓存目录是否存在,如果不存在,创建 os.mkdir(cach_dir) url_dict = {'baidu':'http://www.baidu.com', '52pojie':'http://www.52pojie.cn', } # 创建一个字典,将已经知道的网址放入里面,下次可以继续使用 from urllib.request import urlopen # 导入一个可以下载网页的模块 def wrapper(func): """ 这是个装饰器,主要的作用是接收一个url的路径,然后返回这个网页的代码 :param func: :return: """ def inner(*args, **kwargs): url_name = args[0] # url_name,就是想要下载的网页的名字 sha1 = hashlib.sha1() # 调用加密算法 sha1 sha1.update(url_name.encode()) # 将url 进行加密,得到结果,后期用来查看缓存是否存在 sha1_name = sha1.hexdigest() # 将加密后的 url(字符串) ,赋值给 sha1_name file_name = cach_dir + sha1_name # 确定文件路径 url_dict[args[0].split('.')[1]] = args[0] # 将网页信息写入字典中,如果存在,则更新 if os.path.exists(file_name) and os.path.getsize(file_name) > 0: # 判断缓存文件是否存在,大小是否大于 0 with open(file_name, 'rb') as f: # 打开文件,并且用 rb 二进制的方式打开 print('缓存已经存在,正在读取。。。') time.sleep(2) return f.read() # 将新网址加入字典中 # url_dict[args[0].split('.')[1]] = args[0] # 将网页信息写入字典中,如果存在,则更新 print('正在从网上下载。。。') time.sleep(2) res = func(*args, **kwargs) with open(file_name, 'wb') as f: f.write(res) # input('回车键结束。。。。') return res return inner @wrapper def get(url): return urlopen(url).read() # res = get('http://www.baidu.com') # print(res.decode()) # print(get('http://www.baidu.com').decode()) while True: choose_list = [] # 这里我定义了一个列表,主要是把存放地址的字典的 key 放进去,因为字典是无须的,我想实现输入序号(下表)的方式选择地址,用列表的话,可以实现数字(下标)对应列表元素(字典的keys) for c, i in enumerate(url_dict): # 打印序号,并循环打印字典的keys choose_list.append(i) # 分别将 每个 key 放入到列表中,这样的话,下面打印选项的时候,我就可以通过对应关系找到 用户所选择的网址是哪一个 print(' %s %s %s'%(c+1, i, url_dict[i])) # 将字典中的内容打出来,例如: 1 baidu www.baidu.com choose = input(' 请输入序号或直接输入网址:http://www.baidu.com >>>').strip() # 这里获取一个用户的选择 if choose.upper() == "Q": # 如果选择是 'q' 或者 'Q', 那么退出 break elif choose.isdigit() and 0 < int(choose) <= len(choose_list): # 如果 choose 是数字,而且,数字的大小等于列表的长度(也就是说选择范围为打印菜单的序号) res = get(url_dict[choose_list[int(choose) - 1]]) # 那么,就把这个选择对应的网址传给函数 get(), 得到的返回值给 res print(res) elif 'http://' in choose: # 如果, choose 中包含 'http://' 这几个字符的话,我就认为,你输入了一个完整的网址 res = get(choose) # 这个时候,我就将这个完整的网址传个 get() 函数,将返回值给 res print(res) else: # 如果都不满足,提示输入错误 print('输入错误') time.sleep(2)