您的位置:首页 > 编程语言 > Python开发

Python内置类型(5)--迭代器类型

sesshoumaru 2017-12-18 09:20 162 查看

指能够被内置函数
next
调用并不断返回下一个值,直到最后抛出
StopIteration
错误表示无法继续返回下一个值的对象称为迭代器(
Iterator
)


其实以上的说法只是侠义上的迭代器的定义,在python中,迭代器还需要实现可迭代接口(
Iterable
),可迭代接口需要返回的是一个迭代器对象,这样迭代器就能够被
for
语句进行迭代。

迭代器对象初步认知

python
中,没有内置迭代器类型的对象,但是可以通过内置函数
iter
str
tuple
list
dict
set
等类型转换成一个迭代器对象。

>>> s = 'abc'
>>> next(s)
Traceback (most recent call last):
File "<pyshell#27>", line 1, in <module>
next(s)
TypeError: 'str' object is not an iterator
# 以上报错信息可以看出`str`不是迭代器
>>> it_s = iter(s)
>>> next(it_s)
'a'
>>> next(it_s)
'b'
>>> next(it_s)
'c'
>>> next(it_s)
Traceback (most recent call last):
File "<pyshell#31>", line 1, in <module>
next(it_s)
StopIteration
# 以上报错信息可以看出`iter(str)`是迭代器

通过不断的调用
next(iterator)
方法来获取下一个值,这样其实不怎么方便,
python
提供了更为简洁的方法,即
for
循环。
for
循环每执行一次即相当于调用了一次
next(iterator)
方法,直到捕获到
StopIteration
异常退出循环。

>>> it_s = iter(s)
>>> for c in it_s:
print(c)

a
b
c

# 以上的例子是使用for循环遍历迭代器

模块
collections
中的类型
Iterator
就是迭代器的抽象基类,所有的迭代器都是
Iterator
的实例。即如果一个对象是
Iterator
的实例,则说明此对象是迭代器。

from collections import Iterator

>>> isinstance(s,Iterator)
False

>>> isinstance(it_s,Iterator)
True

# 以上信息证实了`str`不是迭代器,而`iter(str)`是迭代器

如何自己实现一个迭代器

根据
python
鸭子类型的特性,我们自定义的类型中,只要实现了
__next()__
方法,该方法在每次被调用时不断返回下一个值,直到无法继续返回下一个值时抛出
StopIteration
异常即可(
next(iterator
)实际上调用的是iterator内部的
__next()__
方法)。

定义自己的迭代器

>>> class MyIter():

def __init__(self,max_value):
self.current_value = 0
self.max_value = max_value

def __next__(self):
if self.current_value < self.max_value:
result = self.current_value
self.current_value += 1
return result
else:
raise StopIteration

验证
next
方法是否不停返回下一个值

>>> my_iter = MyIter(3)
>>> next(my_iter)
0
>>> next(my_iter)
1
>>> next(my_iter)
2
>>> next(my_iter)
Traceback (most recent call last):
File "<pyshell#31>", line 1, in <module>
next(my_iter)
StopIteration

验证对象是否可以用于
for
循环

>>> my_iter = MyIter(3)
>>> for i in my_iter:
print(i)

Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
for i in my_iter:
TypeError: 'MyIter' object is not iterable

验证对象是否是
Iterator
实例

>>> from collections import Iterator
>>> isinstance(my_iter,Iterator)
False

从上面的验证可以看出仅仅实现
__next()__
方法的对象还不是迭代器,真正的迭代器还需要实现一个可迭代接口
Iterable


Iterator
Iterable
的关系

在模块
collections
中的类型
Iterator
就是迭代器的抽象基类,其实它里面还定义了类型
Iterable
,它是可迭代对象的抽象基类。先分别通过
help
命令查看他们的定义:

>>> from collections import Iterator, Iterable
>>> help(Iterator)
Help on class Iterator in module collections.abc:

class Iterator(Iterable)
|  Method resolution order:
|      Iterator
|      Iterable
|      builtins.object
|
|  Methods defined here:
|
|  __iter__(self)
|
|  __next__(self)
|      Return the next item from the iterator. When exhausted, raise StopIteration
|
|  ----------------------------------------------------------------------
|  Class methods defined here:
|
|  __subclasshook__(C) from abc.ABCMeta
|      Abstract classes can override this to customize issubclass().
|
|      This is invoked early on by abc.ABCMeta.__subclasscheck__().
|      It should return True, False or NotImplemented.  If it returns
|      NotImplemented, the normal algorithm is used.  Otherwise, it
|      overrides the normal algorithm (and the outcome is cached).
|
|  ----------------------------------------------------------------------
|  Data and other attributes defined here:
|
|  __abstractmethods__ = frozenset({'__next__'})

>>> help(Iterable)
Help on class Iterable in module collections.abc:

class Iterable(builtins.object)
|  Methods defined here:
|
|  __iter__(self)
|
|  ----------------------------------------------------------------------
|  Class methods defined here:
|
|  __subclasshook__(C) from abc.ABCMeta
|      Abstract classes can override this to customize issubclass().
|
|      This is invoked early on by abc.ABCMeta.__subclasscheck__().
|      It should return True, False or NotImplemented.  If it returns
|      NotImplemented, the normal algorithm is used.  Otherwise, it
|      overrides the normal algorithm (and the outcome is cached).
|
|  ----------------------------------------------------------------------
|  Data and other attributes defined here:
|
|  __abstractmethods__ = frozenset({'__iter__'})

通过上面的代码,可以清楚的看出迭代器类型
Iterator
继承自可迭代类型
Iterable
,可迭代
Iterable
继承自
object
基类,迭代器
Iterator
类型包含
__iter()__
__next()__
方法,而可迭代类型
Iteratble
仅仅包含
__iter__()
。可迭代对象,通过
__iter()__
返回一个迭代器对象,迭代器对象的
__next()__
方法则实际用于被循环。

完善自己实现一个迭代器

我们现在再将
MyIter
类型实现可迭代接口
Iterable
,即实现
__iter__()
方法。

>>> class MyIter():

def __init__(self,max_value):
self.current_value = 0
self.max_value = max_value

def __iter__(self):
return self

def __next__(self):
if self.current_value < self.max_value:
result = self.current_value
self.current_value += 1
return result
else:
raise StopIteration

验证对象是否可以用于
for
循环

>>> my_iter = MyIter(3)
>>> for i in my_iter:
print(i)

0
1
2

验证对象是否是
Iterator
实例

>>> from collections import Iterator
>>> isinstance(my_iter,Iterator)
True

总结

凡是可作用于
for
语句循环的对象都是
Iterable
可迭代类型。

凡是可作用于
next()
函数的对象都是
Iterator
迭代器类型。

str
tuple
list
dict
set
等类型是
Iterable
可迭代类型,但不是
Iterator
迭代器;通过
Iterable
可迭代类型的
__iter()__
方法可以获得一个
Iterator
迭代器对象,从而使得它们可以被for语句循环。

Python
for
循环本质上就是通过调用
Iterable
可迭代对象的
__iter()__
方法获得一个
Iterator
迭代器对象,然后不断调用
Iterator
迭代器对象
__next()__
方法实现的。
标签: