分离__iter__和__next__方法

时间:2018-08-28 10:54:52

标签: python python-3.x iterator iterable

在Python 3中,通过定义__iter____next__方法同时使类成为可迭代和迭代器是标准过程。但是我很难解决这个问题。以下面的示例为例,该示例创建仅产生偶数的迭代器:

class EvenNumbers:

    def __init__(self, max_):
        self.max_ = max_

    def __iter__(self):
        self.n = 0
        return self

    def __next__(self):
        if self.n <= self.max:
            result = 2 * self.n
            self.n += 1
            return result

        raise StopIteration

instance = EvenNumbers(4)

for entry in instance:
    print(entry)

据我所知(如果我做错了,请纠正我),当我创建循环时,将通过调用内部itr = iter(instance)方法之类的__iter__之类的东西来创建迭代器。预期这将返回一个迭代器对象(该实例是由于定义了__next__而引起的,因此我可以返回self)。要从中获取元素,将调用next(itr),直到引发异常为止。

现在我的问题是:__iter____next__是否以及如何分开,以便后者功能的内容在其他地方定义?什么时候有用?我知道我必须更改__iter__才能返回迭代器。

实现此目的的想法来自该站点(LINK),该站点未说明如何实现此目标。

2 个答案:

答案 0 :(得分:8)

这听起来像使您混淆了迭代器可迭代对象。可迭代对象具有__iter__方法,该方法返回迭代器。迭代器具有__next__方法,该方法返回其下一个值或引发StopIteration。现在在python中,stated的迭代器也是可迭代的(但反之亦然),并且iter(iterator) is iterator因此,迭代器itr应该仅从其__iter__返回方法。

  

迭代器必须具有返回迭代器对象本身的__iter__()方法,因此每个迭代器也是可迭代的,并且可以在接受其他可迭代的大多数地方使用

在代码中:

class MyIter:
   def __iter__(self):
       return self

   def __next__(self):
       # actual iterator logic

如果要创建自定义迭代器类,最简单的方法是从collections.abc.Iterator继承,您可以看到上面定义了__iter__(它也是collections.abc.Iterable的子类) 。然后,您只需要

class MyIter(collections.abc.Iterator):
    def __next__(self):
        ...

当然,有一种更简单的方法来制作迭代器,那就是使用生成器函数

def fib():
    a = 1
    b = 1
    yield a
    yield b
    while True:
        b, a = a + b, b
        yield b

list(itertools.takewhile(lambda x: x < 100, fib()))
# --> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

仅供参考,这是抽象迭代器(可迭代)的(简化)代码

from abc import ABC, abstractmethod

class Iterable(ABC):

    @abstractmethod
    def __iter__(self):
        'Returns an instance of Iterator'
        pass

class Iterator(Iterable, ABC):

    @abstractmethod
    def __next__(self):
        'Return the next item from the iterator. When exhausted, raise StopIteration'
        pass

    # overloads Iterable.__iter__
    def __iter__(self):
        return self

答案 1 :(得分:0)

即使我不完全理解@FHTMitchell的文档段落,我现在也已经掌握了这个概念。我遇到了一个有关如何分离这两种方法的示例,并希望对此进行记录。

我发现一个非常basic tutorial,可以清楚地区分可迭代对象和迭代器(这是我感到困惑的原因)。

基本上,您首先将可迭代对象定义为单独的类:

class EvenNumbers:

    def __init__(self, max_):
        self.max = max_

    def __iter__(self):
        self.n = 0
        return EvenNumbersIterator(self)

__iter__方法仅需要一个定义了__next__方法的对象。因此,您可以这样做:

class EvenNumbersIterator:

    def __init__(self, source):
        self.source = source       

    def __next__(self):
        if self.source.n <= self.source.max:
            result = 2 * self.source.n
            self.source.n += 1
            return result
        else:
            raise StopIteration

这将迭代器部分与可迭代类分开。现在有意义的是,如果我在可迭代的类中定义__next__,则必须返回对该实例本身的引用,因为它基本上一次执行2个工作。