Python中的迭代器与可迭代对象

可迭代对象(Iterable)与迭代器(Iterator)是python中的重要概念,两者容易被弄混淆,这里来总结一下。

for循环

我们通常用for循环遍历一个可迭代对象,比如遍历字符串:

>>> s='abc'
>>> for i in s:
...     print(i)
... 
a
b
c

实际上,for循环做了两件事:调用iter()方法生成迭代器,以及调用next()方法返回迭代的值。听起来可能有点费解,我们来手动调用一下:

>>> s="abc"
>>> i=iter(s)  # 调用iter()函数生成迭代器
>>> type(i)    
<class 'str_iterator'>
>>> next(i)   # 调用next()函数,逐步返回迭代器的值
'a'
>>> next(i)
'b'
>>> next(i)
'c'
>>> next(i)   # 当迭代器内部元素耗尽时,会抛出异常
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

我们可以看到,正如上文所说,iter()方法生成迭代器,把迭代器传入next()方法,返回一次迭代的值,不断重复传入就会不断的向后迭代。迭代器本身是会被“耗尽”的(exhausted),此时会抛出 ‘StopIteration’ 异常,迭代结束。
在这个例子中,字符串是可迭代对象iter(string_obj)则返回迭代器,后者才是真正实现迭代操作的对象。两者好像是紧密相关的,但又有所区别,下面我们分别看一下。

__iter__ 与可迭代对象

可迭代对象就是实现了__iter__(或者__getitem__,本文只讨论前者)魔术方法的对象,其中__iter__返回迭代器。来看一下自己实现的可迭代对象:

class MyIterable:
    def __init__(self):
        self.i = MyIterator()
    def __iter__(self):
        return self.i

例子很简单,其中MyIterator()是迭代器实例,下文会解释; __iter__方法什么都不用做,只需返回一个迭代器实例。这样,我们就实现了一个可迭代对象,也可以用for 循环遍历:

>>> for word in MyIterable():
        print(word)
...
This
is
a
sentence

当然,也可以手动先用Iter(MyIterable)来构造一个迭代器,再用next()逐步遍历。下面我们来看一下到底什么是迭代器。

__next__ 与迭代器

所谓迭代器,就是实现了__next__魔术方法的对象__next__方法负责返回实际的值。当我们使用next()方法时,__next__会被解释器调用。我们来实现一个迭代器:

class MyIterator:
    def __init__(self):
        self.sentence = "This is a sentence".split()
        self.index = 0
        
    def __next__(self):
        try:
            word = self.sentence[self.index]
        except IndexError:
            raise StopIteration()
        self.index += 1
        return word
        

这里 __next__方法一次返回句子中的一个单词。类似的,我们可以手动调用next()方法来遍历:

>>> i = MyIterator()
>>> next(i)
'This'
>>> next(i)
'is'
>>> next(i)
'a'
>>> next(i)
'sentence'
>>> next(i)
...
StopIteration

但这时,Iterator对象本身不能够迭代,因为它仅仅是个迭代器,不是可迭代对象:

>>> i = MyIterator()
>>> for w in i:
         print(w)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'MyIterator' object is not iterable

所以为了兼容,我们可以实现__iter__方法,其返回迭代器对象,在这里也就是返回自身:

    def __iter__(self):
        return self

此时我们便可以迭代MyIterator

>>> i = MyIterator()
>>> for w in i:
...        print(w)
...
This
is
a
sentence

值得注意的是,__iter__方法并不属于迭代器本身的内容,不实现也不会对迭代器产生影响,这里仅仅时为了与可迭代对象兼容而已。

小结

实际上,例子中的可迭代对象可以用更加 “Pythonic” 的方式实现:生成器,这里不再展开。总结一下生成器和迭代器:
  1. 实现__iter__方法的对象即为可迭代对象,该方法返回迭代器对象;
  2. 实现__next__方法的对象即为迭代器,该方法实现了具体的返回值操作;为了兼容可迭代对象,也实现了__iter__方法,返回自身即可;
  3. 无论是__iter__还是__next__,都是在执行iter()next()方法时被解释器调用,for 循环实现了这个过程。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值