注意:
1.构建可迭代对象和迭代器时经常会出现错误,原因是混淆了二者。
(1)可迭代对象有个__iter__( ) 方法,调用该方法每次都实例化一个新的迭代器。
(2)迭代器要实现__next__( )方法返回单个元素,还要实现__iter__( )方法返回本身(self)
因此,迭代器可以迭代,但是可迭代对象不是迭代器!!!
导入模块:from collections.abc import Iterable,Iterator
可以用 isinstance( x , Iterable ) 判断x是否为可迭代对象;
可以用 isinstance( x , Iterator ) 判断x是否为迭代器;
2.生成器是特殊的迭代器
一、可迭代对象 iterable
一句话:“实现了__iter__方法的对象就叫做可迭代对象”
简单点来说能用for循环进行迭代的对象就是可迭代对象。比如:字符串、列表、元组、集合...
注意:
1.调用可迭代对象的__iter__() 方法返回一个可迭代对象(iterable)
2.不断调用迭代器的__next__() 方法返回元素
3.直到迭代完成后,处理StopIteration异常
>>> a = [1,2,3] >>> b = a.__iter__() >>> print(b) <list_iterator object at 0x000001E9C5781860> >>> b.__next__() 1 >>> b.__next__() 2 >>> b.__next__() 3 >>> b.__next__() Traceback (most recent call last): File "<pyshell#6>", line 1, in <module> b.__next__() StopIteration
二、迭代器 iterator
什么叫迭代器?它就是一个带状态的对象,他能在你调用
next()
方法的时候返回容器中的下一个值。任何实现了
__iter__
和__next__()
方法的对象都是迭代器。标准的迭代器接口有两个方法:
(1)__next__( ) :返回下一个可用的元素,如果没有元素,抛出StopIteration异常。
(2)__iter__( ) :返回self,以便在应该使用可迭代对象的地方使用迭代器,比如for循环中。
迭代器就像一个懒加载的工厂,等到有人需要的时候才给它生成值返回,没调用的时候就处于休眠状态等待下一次调用。直到无元素可调用,返回StopIteration异常。
例子如下实现斐波那契数列:
>>> class Fib(): def __init__(self,max): self.n = 0 self.prev = 0 self.curr = 1 self.max = max def __iter__(self): return self def __next__(self): if self.n<self.max: value = self.curr self.curr += self.prev self.prev = value self.n += 1 return value else: raise StopIteration >>> f = Fib(5) >>> next(f) 1 >>> f.__next__() 1 >>> next(f) 2 >>> next(f) 3 >>> next(f) 5 >>> next(f) Traceback (most recent call last): File "<pyshell#32>", line 1, in <module> next(f) File "<pyshell#25>", line 17, in __next__ raise StopIteration StopIteration
三、生成器 generator
注意:生成器是特殊的迭代器(反之不成立),不需要写__iter__( )、__next__( ),只需要一个yield关键字。
在Python中,这种一边循环一边计算的机制,称为生成器:generator
使用next()函数和send()函数恢复生成器
(1)next()函数:next的作用是唤醒并继续执行
(2)send()函数:send的作用是唤醒并继续执行,发送一个信息到生成器内部
生成器类似于返回值为数组的一个函数,这个函数可以接受参数,可以被调用,但是,不同于一般的函数会一次性返回包括了所有数值的数组,生成器一次只能产生一个值,这样消耗的内存数量将大大减小,而且允许调用函数可以很快的处理前几个返回值,因此生成器看起来像是一个函数,但是表现得却像是迭代器.
python提供了两种基本的方式:
(1)生成器函数:用def 定义的利用关键字yield一次性返回一个结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行。如下:
# 例子1:斐波那契数列 def Fib(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1 return '啊哈没有数据了喔' f = Fib(10) # 使用一个循环捕获最后return 返回的值,保存在异常StopIteration的value中 while 1: try: x = next(f) print('f:', x) except StopIteration as e: print('生成器最后返回的值:', e.value) break # 例子2: def foo(): print("first") count=yield print(count) yield f = foo() f.send(None) f.send(2) """ 例子2解释: f = foo() 返回一个生成器 f.send(None) 进行函数执行代码,遇到count = yield,冻结并跳出函数体 f.send(2) 再次进入函数体,接着冻结的代码继续执行,把2传给变量count, 打印count,遇到yield冻结并跳出函数 """
(2)生成器表达式:生成器表达式是列表推导式的生成器版本,看起来像列表推导式,但是它返回的是一个生成器对象而不是列表对象。
from collections.abc import Iterable,Iterator a = (x for x in range(10)) print(isinstance(a,Iterable)) # True print(isinstance(a,Iterator)) # True