(期末卷一卷)python迭代对象,迭代器,生成器,超级详解
一 、定义详解
可迭代对象iterable
可迭代的对象的意思是就是说这个实体是可迭代的,例如字符、列表、元组、字典、迭代器等等,可以用for … in进行循环。
而可以使用for循环迭代的标志是内部实现了__iter__方法。
可迭代对象仅含有__iter__的内部方法,你可以通过封装next()方法(python3中为__next__())来将其做成一个迭代器,以生成器(generator,特殊的函数类型的迭代器)为例,你可以通过yield关键字来做一个迭代器,只不过名字被叫做generator,yield可以看做就是为对象添加了__iter__方法和指示下一次迭代的next()/next()方法。
使用isinstance(实体名,Iterable)可判断是否为可迭代对象
迭代器iterator
迭代器就是实现了迭代方式的容器,iterable对象一般只能按默认的正序方式进行迭代,你可以通过为其添加__next__()/next()方法来定制不同的迭代方式,这样通过next方法封装起来的迭代对象生成器就被称作迭代器。
与iterable相比iterator多了一个next()方法,next()方法用于定制for循环时具体的返回值及返回顺序以及处理StopIteration异常等。
iterator必定是iterable的,因此其必然含有__iter__方法,此方法保证了iterator是可以迭代的,个人认为可以将__iter__()方法看做迭代器的入口,此入口告诉python对象是可for循环的,当你还为class定义了__next__方法时python的for循环会直接调用__next__()方法进行迭代。
因此对于实现了__next__方法的迭代器来讲__iter__方法是一个不可或缺的鸡肋方法,不可或缺是因为他是可迭代的标识,鸡肋是因为他不会实质性的起作用,虽然他是迭代器的入口但却不是迭代的起始点,也因此iterator的__iter__方法可以随意返回self或者self.属性或者None。
使用isinstance(实体名,Iterator)可判断是否为迭代器
生成器generator
generator对象是一种特殊的iterator函数,它会在执行过程中保存执行的上下文环境,并在下次循环中从yield语句后继续执行,生成器的标志就是yield关键字。
generator不需要抛出StopIteration异常(你可以看做yield已经在内部实现了StopIteration跳出循环),函数并没有将序列项一次生成,所以generator在实现上可以有无穷个元素,而不需要无穷的存储空间,这在内存优化方面很有用处。
使用isinstance(实体名,Generator)可判断是否为生成器
二 、生成器是特殊的迭代器,但迭代器不一定是生成器
生成器的创建办法有两种:
(1)通过函数创建,称作generator function
(2)通过推导式创建,例如g=(x*2 for x inrange(10)),称作generator expression
isinstance()
该方法用于判断对象是否为Iterator, Iterable, Generator类型,返回 True/False
from collections import Iterator, Iterable, Generator
a=['ShanXi','HuNan','HuBei','XinJiang','JiangSu','XiZang','HeNan','HeBei']
print(isinstance(a,Iterator)) # 检查a 是否是迭代器
print(isinstance(a,Iterable)) # 检查a 是否是迭代对象
print(isinstance(a,Generator)) # 检查a 是否是生成器
方法1:
对列表a的遍历方法有三种:
(1)、普通遍历 for循环
for province in a:print(province)
(2)、函数生成器遍历
for province in generator_list(a):print(province)
(3)、创建生成器后,利用内置函数next()逐个输出进行遍历
print(next(iter))
print(next(iter))
print(next(iter))
def generator_list(a):
for e in a:
yield 'Province:\t' + e # 注意yield为生成器标志
# for province in generator_list(a):
# print(province)
# for province in a:
# print(province)
iter=generator_list(a)
print(next(iter))
print(next(iter))
print(next(iter))
print(isinstance(iter,Iterator)) # 检查a 是否是迭代器
print(isinstance(iter,Iterable)) # 检查a 是否是迭代对象
print(isinstance(iter,Generator)) # 检查a 是否是生成器
(----再次提醒----)生成器一定是迭代器,但迭代器不一定是生成器
方法2:直接创建迭代器类 :内含两种标志方法 iter(self) next(self)
class iterator_list(object):
def __init__(self,a):
self.a=a
self.len=len(self.a)
self.cur_pos=-1
def __iter__(self): # (象征性入口)
return self
def __next__(self): # Python3中只能使用__next__()而Python2中只能命名为next()
self.cur_pos +=1
if self.cur_pos<self.len:
return self.a[self.cur_pos]
else:
raise StopIteration() # 表示至此停止迭代
iter=iterator_list(a)
print(isinstance(iter,Iterator)) # 检查a 是否是迭代器
print(isinstance(iter,Iterable)) # 检查a 是否是迭代对象
print(isinstance(iter,Generator)) # 检查a 是否是生成器
print(next(iter))
print(next(iter))
print(next(iter))
三、为什么列表本身就可以for循环遍历,还要创建迭代器呢?
你可以理解为,一个程序中创建了不同功能的迭代器类,随时可以调用,代码利用效率高,使用方便。
下面是个实例,加强理解。
list=['a','b','c','d','e','f','g','h','i','j']
# 创建两个迭代器: 一个正序,一个反序,只需要通过两个类就可以方便地创建迭代器对象,不需要频繁地通过for循环遍历序列
class iter_standard(object):
def __init__(self,list):
self.list=list
self.len = len(self.list)
self.cur_pos = -1
def __iter__(self):
return self
def __next__(self):
self.cur_pos += 1
if self.cur_pos<self.len:
return self.list[self.cur_pos]
else:
raise StopIteration()
class iter_reverse(object):
def __init__(self,list):
self.list=list
self.len = len(self.list)
self.cur_pos = self.len
def __iter__(self):
return self
def __next__(self):
self.cur_pos -= 1
if self.cur_pos>=0:
return self.list[self.cur_pos]
else:
raise StopIteration()
for e in iter_standard(list):
print (e)
print("*"*20)
for e in iter_reverse(list):
print (e)