可迭代对象/迭代器/生成器
字典、序列(包括字符串、列表和元组)、迭代器(iterator)、生成器(generator)都是可迭代对象
- 定义可迭代对象必须实现__iter__()方法
- 定义迭代器必须实现__iter__()和__next__()方法
-
__iter__方法返回迭代器类的实例,__next__方法返回迭代的每一步结果,实现该方法时,超出边界要抛出StopIteration异常
可迭代对象与迭代器的具体例子:
class MyList(object): # 定义可迭代对象类 def __init__(self, num): self.data = num # 上边界 def __iter__(self): return MyListIterator(self.data) # 返回该可迭代对象的迭代器类的实例 class MyListIterator(object): # 定义迭代器类,其是MyList可迭代对象的迭代器类 def __init__(self, data): self.data = data # 上边界 self.now = 0 # 当前迭代值,初始为0 def __iter__(self): return self # 返回该对象的迭代器类的实例;因为自己就是迭代器,所以返回self def __next__(self): # 迭代器类必须实现的方法 while self.now < self.data: self.now += 1 return self.now - 1 # 返回当前迭代值 raise StopIteration # 超出上边界,抛出异常 my_list = MyList(5) # 得到一个可迭代对象 print(type(my_list)) # 返回该对象的类型 my_list_iter = iter(my_list) # 得到该对象的迭代器实例(iter用于创建迭代器。iter()直接调用对象的__iter__(),并把__iter__()的返回结果作为自己的返回值;next(iterator/generator)输出迭代器的下一个元素,迭代器只能往前不能往后,生成器可通过send往后) print(type(my_list_iter)) for i in my_list: # python解释器会在第一次迭代时自动调用iter(obj),之后的迭代会调用迭代器的__next__()方法,for语句会自动处理最后抛出的StopIteration异常 print(i)
输出
<class '__main__.MyList'> <class '__main__.MyListIterator'> 0 1 2 3 4
- 生成器是一种特殊的迭代器,生成器通过yield关键字自动实现了迭代器协议(即__iter__()和__next__()方法),不需要手动实现两个方法
- yield可以理解为return,返回后面的值给调用者。不同的是return返回后,函数会被释放,而生成器则不会。 在直接调用next方法或用for语句进行下一次迭代时,生成器会从yield下一句开始执行,直至遇到下一个yield
-
生成器在迭代过程中可通过send改变当前的迭代值
生成器的具体例子:
def myList(num): # 定义生成器 now = 0 # 当前迭代值,初始为0 while now < num: val = (yield now) # 返回当前迭代值,并接受通过send重新设置当前迭代值 now = now + 1 if val is None else val # val为None,迭代值自增1,否则重新设定当前迭代值为val my_list = myList(5) # 得到一个生成器对象 print(type(my_list)) print(next(my_list)) # 返回当前迭代值 print(next(my_list)) my_list.send(0) # 重新设定当前的迭代值 往后跳跃 print(next(my_list)) my_list.send(3) # 重新设定当前的迭代值 往前跳跃 print(next(my_list)) print(dir(my_list)) # 返回该对象所拥有的方法名,可以看到__iter__与__next__在其中
输出
<class 'generator'> 0 1 1 4 ['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__name__', '__ne__', '__new__', '__next__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw']