迭代器和生成器
一、迭代器
迭代器即迭代取值的工具,迭代是一个重复的过程,每一次重复都是基于上一次的结果而来,迭代的目的通常是为了取得某一想要的结果。
基于索引的迭代器取值方式只适用于列表、元组、字符串类型,而对于没有索引的字典、集合、文件则不在适用。所以必须找到一种通用的并且不依赖于索引的迭代器取值方式:迭代器。
1.可迭代对象
在python中但凡内置有__iter__方法的对象都是可迭代的对象,如字符串、列表、元组、字典、集合、文件等都是可迭代的对象。
a='123'
print(a.__iter__())
b=[1,2,3]
print(b.__iter__())
<<< <str_iterator object at 0x000002A5C9726FD0>
<<< <list_iterator object at 0x000002A5C9726FD0>
2.迭代器
迭代器指的是既内置有__iter__方法,又内置有__next__方法的对象。执行可迭代对象的__iter__方法得到的就是内置的迭代器对象,文件句柄本身就是迭代器。
迭代器对象一定是可迭代对象,而可迭代对象则不一定是迭代器。
执行迭代器对象的__next__方法可以取出迭代器中的一个值,当迭代器中值取完以后再执行__next__方法会报StopIteration。迭代器是python提供的一种不通过索引取值的方法,只要存在多个值,无论是否是序列类型都可以通过迭代器的方式取值。
a={1,2,3}
a=a.__iter__()
print(a.__next__())
print(a.__next__())
print(a.__next__())
print(a.__next__())
<<<1
<<<2
<<<3
<<<StopIteration
3.for语句的基本原理
为什么可迭代对象变成迭代器以后,内部还有__iter__方法呢?迭代器的__iter__方法是为了符合for语句原理而存在的,for语句工作时每次都会调用到对象的__iter__方法。
for语句执行的步骤:
- 调用__iter__方法转遍历对象为迭代器(迭代器调用__iter__以后还是迭代器)
- 调用__next__方法取迭代器的值
- 循环以上步骤
- 迭代器取完值退出
用while循环模拟for循环遍历可迭代对象/迭代器:
g=[1,2,3]
g=g.__iter__()
while True:
try:#try语句会在报错时跳转到ecept语句
print(g.__next__())
except StopIteration:
break
<<<1
<<<2
<<<3
4.迭代器的优缺点
优点:
- 提供了一种通用的、可以不依赖索引的迭代取值方式
- 迭代器对象更加节省内存(迭代器是每取一个值才把取的值读入内存中)
缺点:
- 迭代器的取值不如按照索引的方式更灵活,因为它只能往后取不能往前退
- 无法预测迭代器值的个数
二、生成器
在函数内但凡出现yield关键字,再调用函数就不会执行函数体代码,会返回值一个值,该值称之为生成器生成器,本质就是迭代器。
1.生成器的使用方式
生成器是一种自定义迭代器的方式。
def add(x):
while x<3:
x+=1
yield x
g=add(1)#g为生成器对象
print(g.__iter__)
print(g.__next__())#add执行到yield处返回x的值并停滞
print(g.__next__())
print(g.__next__())#x=3不满足循环条件,循环结束,函数中没有yield报StopIteration
<<< <method-wrapper '__iter__' of generator object at 0x000001D0F38D69E0>
<<<2
<<<3
<<<StopIteration
用for遍历生成器:
def add(x):
while x<5:
x+=1
yield x
for i in add(1):
print(i)
<<<2
<<<3
<<<4
<<<5
2.yield关键字
yield关键字可以给函数内部的变量传值:
def eater():
print('preparing now')
while True:
food=yield
print(food)
g=eater()
g.__next__()#给food传值前必须先使用__next__方法让生成器运行至yield处
g.send('花生')
g.__next__()#相当于g.send(None)
<<<preparing now
<<<花生
<<<None
yield也可以同时赋值返回值
def eater():
food_list=[]
print('preparing now')
while True:
food=yield food_list
food.append(food)
def eater():
food_list=[]
print('preparing now')
while True:
food=yield food_list
food_list.append(food)
g=eater()
print(g.__next__())
print(g.send('花生'))
print(g.send('土豆'))
<<<preparing now
<<<[]
<<<['花生']
<<<['花生', '土豆']
3.三元表达式与多种生成式
三元表达式:
res=条件成立时的返回值 if 条件 else 条件不成立时的返回值
x,y=10,20
res=x if x>y else y
res
<<<20
列表生成式:
[res for item1 in iterable1 if condition1
for item2 in iterable2 if condition2
…
]
#生成存放1到10的列表
[i for i in range(1,11)]
<<<[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
生成器生成式:
(res for item1 in iterable1 if condition1)
(i for i in range(1,11))
<<<<generator object <genexpr> at 0x00000274534CD430>
字典生成式:
{k:v for item1,item2 in iterable1 if condition1}
{k: v for k,v in enumerate(range(5,10))}
<<<{0: 5, 1: 6, 2: 7, 3: 8, 4: 9}
集合生成式:
{ res for item1 in iterable1 if condition1}
{i for i in range(1, 11)}
<<<{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}