概述
迭代是数据处理的基石,扫描内存中放不下的数据时,我们需要找到一种惰性获取数据项的方式,即按需一次获取一个数据项。这就是迭代器模式。
在python中,所有集合都可以迭代。在python语言内部,迭代器用于支持:
(1)for循环
(2)构建和扩展集合类型
(3)逐行遍历文本文件
(4)列表推导,字典推导和集合推导
(5)元组拆包
(6)调用函数时,用*拆包
python没有宏,因此为了抽象出迭代器模式,需要改动语言本身,为此加入了yield用于构建生成器。所有生成器都是迭代器,反之则不是。迭代器用于从集合中取出元素,而生成器用于凭空产生元素。
iter函数
解释器需要迭代对象x时,会主动调用iter(x)。内置iter函数有以下作用:
(1)检查对象是否实现了__iter__方法,如果实现了就调用它,获取一个迭代器。
(2)如果没有实现__iter__方法,但是实现了_getitem__方法,python会创建一个迭代器,尝试按顺序(从索引0开始)获取元素。
(3)如果尝试失败,python抛出TypeError异常,通常会提示对象不可迭代。
任何序列都可以迭代,其原因是,它们都实现了__getitem__方法。其实,标准的序列也都实现了__iter__方法。
实现了__iter__方法,就认为对象是可以迭代的,此时,不需要创建子类,也不用注册,因为abc.Iterable类实现了__subclasshook__方法。
class Foo:
def __iter__(self):
pass
from collections import abc
print(issubclass(Foo, abc.Iterable))
f = Foo()
print(isinstance(f, abc.Iterable))
#结果
True
True
而只实现了__getitem__方法的类,虽然可以迭代,但是无法通过issubclass测验。
迭代对象之前显示检查对象是否可以迭代或许没有必要,毕竟尝试迭代不可迭代的对象时,会抛出对象不可迭代的异常。如果除了抛出异常还有进一步处理,可以使用try/catch块。
iter函数还可以传入两个参数,使用常规函数或任何可调用对象创建迭代器。这样使用时,第一个参数必须是可调用对象,用于不断调用,产出各个值,另一个值是哨符,这个是标记值,当可调用对象返回这个值时会抛出StopIteration异常,而不产生哨符。
使用iter函数掷筛子,指代掷出1点:
from random import randint
def d6():
return randint(1, 6)
d6_iter = iter(d6, 1)
print(d6_iter)
for roll in d6_iter:
print(roll)
#结果
<callable_iterator object at 0x00000264FD3C54A8>
4
4
2
5
5
5
可迭代对象
可迭代的对象:使用iter内置函数可以获取迭代器的对象。如果对象实现了能返回迭代器的__iter__函数,那么对象就是可以迭代的。序列都可以迭代;实现了__getitem__方法,而