迭代器、生成式、生成器
目录:
概要:
生成式:一次性生成所有数据,然后保存在内存中,适合小量数据 |
迭代器:
1. 什么是迭代器
迭代指的是一个重复的过程,每一次重复都是基于上一次的结果而来的
迭代器指的是迭代取值的工具,该工具的特点是可以不依赖于索引取值
#原始的迭代方法 li=['a','b','c','d','e'] li=('a','b','c','d','e') li='hello' i=0 while i < len(li): print(li[i]) i+=1
2. 为何要用迭代器
为了找出一种通用的&可以不依赖于索引的迭代取值方式
3. 如何用迭代器
可迭代的对象:但凡内置有.__iter__方法的对象都称之为可迭代的对象
迭代器对象:既内置有__iter__方法,又内置有__next__方法
关于__iter__方法:
调用可迭代对象的__iter__会得到一个迭代器对象
调用迭代器对象的__iter__会得到迭代器本身
4. 总结迭代器的优缺点:
优点:
1. 提供了一种通用的&可以不依赖于索引的迭代取值方式
2. 同一时刻在内存中只有一个值,更加节省内存(老母鸡,Python3的rang()方法就相当于一只老母鸡)
缺点:
1. 取指定值不如索引灵活,并且迭代器是一次性的
2. 无法预知迭代器数据的个数
迭代器对象:
可迭代的对象: str,list,tuple,dict,set,文件对象(除了数字类型)
迭代器对象: 文件对象
可迭代的对象=====》迭代器对象:调用可迭代对象内置的__iter__方法会有一个返回值,该返回值就是对应的迭代器对象
#基本语法
dic={'x':1,'y':2,'z':3} iter_dic=dic.__iter__() print(iter_dic) #<dict_keyiterator object at 0x0000000001D97728> res1=iter_dic.__next__() print(res1) #x
res2=iter_dic.__next__()
print(res2)
res3=iter_dic.__next__()
print(res3)
#超出迭代器数据个数,报错
res4=iter_dic.__next__()
print(res4)
print(dic.__iter__().__next__())#x
print(dic.__iter__().__next__())#x
print(dic.__iter__().__next__())#x
通过循环来捕捉异常,避免取值越界后报错:
1 dic={'x':1,'y':2,'z':3} 2 # dic=['a','b','c'] 3 iter_dic=dic.__iter__() 4 5 iter_dic=open(r'今日内容',mode='rt',encoding='utf-8')#文件为迭代器对象 6 7 while True: 8 try: 9 print(iter_dic.__next__()) 10 except StopIteration: 11 break
for循环原理:
for准确地说应该是迭代器循环,for循环的原理如下:
1. 先调用in后面那个值的__iter__方法,得到迭代器对象
2. 执行迭代器.__next__()方法得到一个返回值,然后赋值给一个变量k,运行循环体代码
3. 循环往复,直到迭代器取值完毕抛出异常然后捕捉异常自动结束循环
1 dic={'x':1,'y':2,'z':3} 2 iter_dic=dic.__iter__() 3 print(iter_dic) 4 print(iter_dic.__iter__()) 5 6 for k in dic: # iter_dic=dic.__iter__() | k=iter_dic.__next__() 7 print(k) 8 # <dict_keyiterator object at 0x0000000000477728> 9 # <dict_keyiterator object at 0x0000000000477728> 10 # x 11 # y 12 # z
with open(r'今日内容',mode='rt',encoding='utf-8') as f:
for line in f: #iter_f=f.__iter__()
print(line)
自定义迭代器:
yield关键字:只能用在函数内
在函数内但凡包含有yield关键字,再去执行函数,就不会立刻运行函数体代码了,会得到一个返回值,该返回值称之为生成器对象,生成器本质就是迭代器
总结yield:
1. 提供一种自定义迭代器的解决方案
2. yield可用于返回值
yield VS return
相同点:都可以用于返回值
不同点:yield可以暂停函数,yield可以返回多次值,而return只能返回值一次值函数就立刻终止
1 def func(): 2 print('=====>第一次') 3 yield 1 4 print('=====>第二次') 5 yield 2 6 print('=====>第三次') 7 yield 3 8 print('=====>第四次') 9 10 g=func() 11 print(g.__iter__().__iter__().__iter__() is g) 12 iter(g) #g.__iter__() 13 res=next(g) #g.__next__() 14 print(res) 15 16 res1=next(g) 17 print(res1) 18 19 res2=next(g) 20 print(res2) 21 22 res3=next(g) #报错,取不到 23 print(res3) 24 # True 25 # =====>第一次 26 # 1 27 # =====>第二次 28 # 2 29 # =====>第三次 30 # 3 31 # =====>第四次
自定义一个rang函数:
def my_range(start,stop,step=1): while start < stop: yield start start+=step res=my_range(1,5,step=2) # 1 3 print(next(res)) #1 print(next(res)) #3 for item in res: #还在同一个迭代器中,此时res已经到3,步长为2,没有下一个值 print(item) #打印不到结果 for item in my_range(1,5,2): #这是一个新的迭代器 print(item) #1,3
三元表达式:
原始操作: def max2(x,y): if x > y: return x else: return y 简化操作: x=10 y=20 res=x if x > y else y print(res)
XXX生成式:
列表生成式:列表
将大于4的数字添加到egg后,存入列表:
#原始操作: l=[] for i in range(1,11): if i > 4: res='egg%s' %i l.append(res) print(l) #简化操作: l=['egg%s' %i for i in range(1,11) if i > 4] print(l)
#['egg5', 'egg6', 'egg7', 'egg8', 'egg9', 'egg10']
将除了egon外的名字后加上_DSB,然后存入一个列表:
#原始操作: names=['egon','lxx','yyx','cw','alex','wxx'] l=[] for name in names: if name != 'egon': res='%s_DSB' %name l.append(res) print(l) #简化操作: l=['%s_DSB' %name for name in names if name != 'egon'] print(l)
#['lxx_DSB', 'yyx_DSB', 'cw_DSB', 'alex_DSB', 'wxx_DSB']
字典生成式:字典
items=[('name','egon'),('age',18),('sex','male')]
#原始方法:
dic={}
for k,v in items:
dic[k]=v
print(dic)
#简化方法:
res={k:v for k,v in items if k != 'sex'}
print(res) #{'name': 'egon', 'age': 18}
res={i for i in 'hello'}
print(res)
#{'o', 'h', 'e', 'l'} 去重,逐个,无序
生成器表达式(实际也是一个迭代器):
res=(i**2 for i in range(3)) print(res) #本身是一个迭代器,只有调用next方法,才能取到值,什么也不会打印 print(next(res)) print(next(res)) print(next(res)) #0 #1 #4
1 with open(r'今日内容',mode='rt',encoding='utf-8') as f: 2 data=f.read() 3 print(len(data)) #1025 4 5 with open(r'今日内容', mode='rt', encoding='utf-8') as f: 6 res=0 7 for line in f: 8 res+=len(line) 9 print(res)#1025 10 11 with open(r'今日内容',mode='rt',encoding='utf-8') as f: 12 res=sum((len(line) for line in f)) 13 # res=sum(len(line) for line in f)#有双重小括号,可以省略一个 14 print(res) 15 16 with open(r'今日内容', mode='rt', encoding='utf-8') as f: 17 res=max([len(line) for line in f]) #60 18 #res=max((len(line) for line in f)) #60 19 #res=max(len(line) for line in f) #60 20 print(res)