迭代器对象总结

几个概念
可迭代对象(Iterable):可以使用for循环遍历出所有元素的都可以称为可迭代对象,列表、元组、字符串、字典等都是可迭代对象,迭代器一定是可迭代对象,反之不一定成立,如字符串;内部实现了__iter__方法的对象;可迭代对象不一定实现__next__方法,它可以不遵循迭代器协议,至于为啥可有for循环,是因为for循环内部调用了他的__iter__方法,返回的结果是遵循了迭代器协议的迭代器对象(自然就有了__next__方法)
迭代器协议:一个对象要想成为迭代器对象必须遵循的规则“对象内部同时实现了__iter__和__next__方法,执行__next__方法返回迭代器中的下一项,最后一个元素返回后再调用raise一个StopIteration异常,结束迭代”
迭代器对象(Iterator):遵循迭代器协议规则的对象,迭代器必须实现__iter__方法和__next__方法,像文件句柄,本身就有__next__方法

指能够被内置函数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异常退出循环。

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

a
b
c
# 以上的例子是使用for循环遍历迭代器
模块collections中的类型Iterator就是迭代器的抽象基类,所有的迭代器都是Iterator的实例。即如果一个对象是Iterator的实例,则说明此对象是迭代器。
from collections import Iterator,Iterable
>>> s = "abc"
>>> it_s = iter(s)
>>> isinstance(s,Iterator)
False
>>> isinstance(s,Iterable)
True
>>> isinstance(it_s,Iterator)
True
# 以上信息证实了`str`不是迭代器Iterator,是可迭代的Iterable,而`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()__方法实现的。
  • 10
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值