Python迭代器

194 阅读2分钟

Python迭代器

可迭代对象(Iterable)和迭代器(Iterator)的区别

可迭代对象(Iterable)

官方释义: 能够逐一返回其成员项的对象

常见的可迭代对象:

所有的有序类型某些非序列类型其他对象
listdict定义__iter__()
str文件对象实现了Sequence语义的__getitem__()方法
tuple……
……

迭代器(Iterator)

官方释义: 用来表示一连串数据流的对象

常见的迭代器:

常见其他对象
zip具有__iter__()__next__()方法
map

区别

翻看源码(Python3.7)能明显看出区别

list

 class list(object):
     """
     Built-in mutable sequence.
     
     If no argument is given, the constructor creates a new empty list.
     The argument must be an iterable if specified.
     """
     # 省略一大堆代码
     def __iter__(self, *args, **kwargs): # real signature unknown
         """ Implement iter(self). """
        pass

map:

 class map(object):
     """
     map(func, *iterables) --> map object
     
     Make an iterator that computes the function using arguments from
     each of the iterables.  Stops when the shortest iterable is exhausted.
     """
     def __iter__(self, *args, **kwargs): # real signature unknown
         """ Implement iter(self). """
         pass
     # 省略一大堆代码
     def __next__(self, *args, **kwargs): # real signature unknown
         """ Implement next(self). """
         pass

可迭代对象具有__iter__()方法,迭代器本身是一个可迭代的对象还拥有__next__()方法。

For循环的背后

迭代器最频繁使用的场景之一就是for循环之中。

在遍历可迭代对象的时候,会为这个可迭代对象创建一个迭代器,然后执行循环体语句,直至遍历完成

graph LR
A[需要遍历的对象] -->B{可迭代判断}
B --> |__iter__| C(创建迭代器对象)
B --> |无__iter__| D(报错: object is not iterable)
C --> E{判空}
E --> |序列为空| F(终止循环)
E --> |迭代器引发 StopIteration 异常| F(终止循环)

当一个迭代器空了后,在进行next()方法的调用会出现 StopIteration 异常,而for循环利用try...except...抓住这个错误使其能够正常运行。

优雅的判断对象是否为可迭代对象(Iterable)或迭代器(Iterator)

 #引入可迭代对象和迭代器
 from collections.abc import Iterable, Iterator
 ​
 numList = [3, 2, 5, 1, 9, 11]
 ​
 print(isinstance(numList, Iterable)) #True
 print(isinstance(numList, Iterator)) #False
 # 创造一个迭代器
 numIterator = iter(numList)
 ​
 print(isinstance(numIterator, Iterator)) #True
 ​

除了这样判断一些原有的对象,也可以自定义一个迭代器,根据前面的内容可以知道,迭代器必须拥有__iter__()__next__()方法,再根据Python3.7的文档所述:

迭代器必须使 __iter__() 方法用来返回该迭代器对象自身

 # 将传入的列表的数字+10并输出
 class AddTen:
     def __init__(self, args_list):
         self.mylist = args_list
         self.endIndex = len(args_list)
         self.index = 0
 ​
     def __iter__(self):
         return self
 ​
     def __next__(self):
         if self.index == self.endIndex:
             raise StopIteration
 ​
         self.mylist[self.index] += 10
         self.index += 1
         return self.mylist[self.index - 1]
     
 newAddTen = AddTen(numList)
 ​
 print(isinstance(newAddTen, Iterator))
 print(next(newAddTen))
 print(next(newAddTen))
 print(next(newAddTen))
 print(next(newAddTen))
 print(next(newAddTen))
 print(next(newAddTen))
 print(next(newAddTen))

Iterator.png

小结

只有__iter__()是可迭代对象(Iterable),有__iter__()__next__()的是迭代器(Iterator),根据自定义的迭代器可以看出迭代器具有Lazy Load的特性,用多少取多少方便处理超大量数据。

本文参考于 Python 3.7.12 文档

\