day20:有参装饰器、迭代器
要求不同的函数要用不通的认证方式,就需要用有参装饰器。有参装饰器也就是在无参装饰器外面再包一层函数,带上参数。
def deco(auth_type='file'): def auth(func): def wrapper(*args,**kwargs): if auth_type == 'file': print('文件的认证方式') elif auth_type == 'ldap': print('ldap认证方式') elif auth_type == 'mysql': print('mysql认证方式') else: print('不知到的认证方式') return wrapper return auth @deco(auth_type='abc') #@auth #index=auth(index) def index(): print('welecome to index') @deco(auth_type='ldap') def home(name): print('welecome %s to home page' %name) index() home('egon')
迭代器
迭代:
1 重复
2 下一次重复是基于上一次的结果
可以直接作用于for
循环的数据类型有以下几种:
list
、tuple
、dict
、set
、str
等;generator
,包括生成器和带yield
的generator functionfor
循环的对象统称为可迭代对象:Iterable
isinstance()
判断一个对象是否是Iterable
对象:>>> from collections import Iterable >>> isinstance([], Iterable) True >>> isinstance({}, Iterable) True >>> isinstance('abc', Iterable) True >>> isinstance((x for x in range(10)), Iterable) True >>> isinstance(100, Iterable) False
而生成器不但可以作用于for
循环,还可以被next()
函数不断调用并返回下一个值,直到最后抛出StopIteration
错误表示无法继续返回下一个值了。
可以被next()
函数调用并不断返回下一个值的对象称为迭代器:Iterator
。
可以使用isinstance()
判断一个对象是否是Iterator
对象:
>>> from collections import Iterator >>> isinstance((x for x in range(10)), Iterator) True >>> isinstance([], Iterator) False >>> isinstance({}, Iterator) False >>> isinstance('abc', Iterator) False
生成器都是Iterator
对象,但list
、dict
、str
虽然是Iterable
,却不是Iterator
。
把list
、dict
、str
等Iterable
变成Iterator
可以使用iter()
函数:
>>> isinstance(iter([]), Iterator) True >>> isinstance(iter('abc'), Iterator) True
你可能会问,为什么list
、dict
、str
等数据类型不是Iterator
?
这是因为Python的Iterator
对象表示的是一个数据流,Iterator对象可以被next()
函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration
错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()
函数实现按需计算下一个数据,所以Iterator
的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator
甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
小结
凡是可作用于for
循环的对象都是Iterable
类型;
凡是可作用于next()
函数的对象都是Iterator
类型,它们表示一个惰性计算的序列;
集合数据类型如list
、dict
、str
等是Iterable
但不是Iterator
,不过可以通过iter()
函数获得一个Iterator
对象。
迭代器的优点
1:提供了一种不依赖于索引的取值方式
2:惰性计算。节省内存
迭代器的缺点:
1:取值不如按照索引取值方便
2:一次性的。只能往后走不能往前退
3:无法获取长度
Python的for
循环本质上就是通过不断调用next()
函数实现的,例如:
for x in [1, 2, 3, 4, 5]: pass
实际上完全等价于:
# 首先获得Iterator对象: it = iter([1, 2, 3, 4, 5]) # 循环: while True: try: # 获得下一个值: x = next(it) except StopIteration: # 遇到StopIteration就退出循环 break
一、编写日志装饰器,实现功能如:一旦函数f1执行,则将消息2017-07-21 11:12:11 f1 run写入到文件中
注意:时间格式的获取
import time log_file = r'C:\Users\zzn\PycharmProjects\python3\day1\b.txt' def time_add(func): def wrapper(*args,**kwargs): with open(log_file,'a',encoding='utf-8') as f: func() res = '%s %s run\n' %(time.strftime('%Y-%m-%d %X'),func.__name__ ) f.write(res) return wrapper @time_add def f1(): print('运行f1程序') f1()
二、 选做题:
基于课上所讲网页缓存装饰器的基础上,实现缓存不同网页的功能
要求,用户提交的不同url,都能缓存下来,对相同的url发起下载请求,
优先从缓存里取内容
from urllib.request import urlopen import os cache_path = r'C:\Users\zzn\PycharmProjects\python3\day1\cache_day8' def add_dic(func): def wrapper(*args,**kwargs): ret = func(*args, **kwargs) t = str(args).strip('()') t = t.split('/') cache_1 = os.path.join(cache_path,t[2]) if os.path.isfile(cache_1): if os.path.getsize(cache_1): with open(cache_1, 'rb') as f: print('读缓存') ret = f.read() else: with open(cache_1,'wb') as f: print('创建') f.write(ret) return ret return wrapper @add_dic def get(url): return (urlopen(url).read()) print(get('http://www.renren.com/')) print(get('http://www.baidu.com/'))