Python中的“iterable”、“iterator”和“iteration”是什么?它们是如何定义的?


当前回答

Iterable:-可迭代的东西是可迭代的;比如序列,比如列表,字符串等等。 它也有__getitem__方法或__iter__方法。现在如果我们对该对象使用iter()函数,我们将得到一个迭代器。

迭代器:-当我们从iter()函数获得迭代器对象;我们调用__next__()方法(在python3中)或简单地调用next()(在python2中)来逐个获取元素。该类或该类的实例称为迭代器。

从文档:

迭代器的使用遍及并统一了Python。在后台,for语句在容器对象上调用iter()。该函数返回一个迭代器对象,该对象定义了__next__()方法,该方法每次访问容器中的一个元素。当没有更多的元素时,__next__()会引发一个StopIteration异常,告诉for循环终止。你可以使用next()内置函数调用__next__()方法;这个例子展示了它是如何工作的:

>>> s = 'abc'
>>> it = iter(s)
>>> it
<iterator object at 0x00A1DB50>
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
    next(it)
StopIteration

一个类的前:-

class Reverse:
    """Iterator for looping over a sequence backwards."""
    def __init__(self, data):
        self.data = data
        self.index = len(data)
    def __iter__(self):
        return self
    def __next__(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]


>>> rev = Reverse('spam')
>>> iter(rev)
<__main__.Reverse object at 0x00A1DB50>
>>> for char in rev:
...     print(char)
...
m
a
p
s

其他回答

上面的答案很好,但就我所见,对像我这样的人来说,没有足够的区别。

此外,人们倾向于把“X是一个具有__foo__()方法的对象”这样的定义放在前面,从而变得“过于python化”。这样的定义是正确的——它们基于duck-typing哲学,但是在试图理解概念的简单性时,对方法的关注往往会变得偏颇。

所以我添加了我的版本。


在自然语言中,

迭代是在一行元素中每次取一个元素的过程。

在Python中,

Iterable是一个对象,它是可迭代的,简单地说 它可以在迭代中使用,例如使用for循环。如何?通过使用迭代器。 我将在下面解释。 ... 而iterator是一个对象,它定义了如何实际执行 迭代——特别是下一个元素是什么。这就是为什么它一定是 next()方法。

迭代器本身也是可迭代的,区别在于它们的__iter__()方法返回相同的对象(self),而不管它的项是否已被之前对next()的调用所消耗。


那么,当Python解释器在obj: statement中看到for x时,它会怎么想?

看,一个for循环。看起来像是迭代器的工作…让我们买一个. ... 这里有个obj,我们来问他。 " obj先生,你有迭代器吗"(…调用iter(obj),它调用 Obj.__iter__(),它愉快地分发了一个闪亮的新迭代器_i。) 好吧,这很简单……让我们开始迭代。(x = _i.next()…X = _i.next()…

因为Mr. obj在这个测试中成功了(通过让某个方法返回一个有效的迭代器),我们用一个形容词来奖励他:你现在可以称他为“可迭代的Mr. obj”。

然而,在简单的情况下,将迭代器和iterable分开使用通常没有什么好处。所以你只定义了一个对象,它也是它自己的迭代器。(Python并不真正关心obj传递的_i是不是那么闪亮,而只是obj本身。)

这就是为什么在我看到的大多数例子中(也是让我一次又一次困惑的例子), 你可以看到:

class IterableExample(object):

    def __iter__(self):
        return self

    def next(self):
        pass

而不是

class Iterator(object):
    def next(self):
        pass

class Iterable(object):
    def __iter__(self):
        return Iterator()

不过,在有些情况下,将迭代器与可迭代对象分开可以带来好处,比如当你想要有一行项,但有更多的“游标”时。例如,当您想要处理“当前”和“即将”元素时,可以为这两个元素使用单独的迭代器。或者从一个巨大的列表中抽取多个线程:每个线程都有自己的迭代器来遍历所有项。请看上面@Raymond和@glglgl的回答。

想象一下你能做什么:

class SmartIterableExample(object):

    def create_iterator(self):
        # An amazingly powerful yet simple way to create arbitrary
        # iterator, utilizing object state (or not, if you are fan
        # of functional), magic and nuclear waste--no kittens hurt.
        pass    # don't forget to add the next() method

    def __iter__(self):
        return self.create_iterator()

注:

I'll repeat again: iterator is not iterable. Iterator cannot be used as a "source" in for loop. What for loop primarily needs is __iter__() (that returns something with next()). Of course, for is not the only iteration loop, so above applies to some other constructs as well (while...). Iterator's next() can throw StopIteration to stop iteration. Does not have to, though, it can iterate forever or use other means. In the above "thought process", _i does not really exist. I've made up that name. There's a small change in Python 3.x: next() method (not the built-in) now must be called __next__(). Yes, it should have been like that all along. You can also think of it like this: iterable has the data, iterator pulls the next item

免责声明:我不是任何Python解释器的开发人员,所以我真的不知道解释器“在想什么”。上面的思考仅仅是我从其他解释、实验和一个Python新手的实际经验中对这个主题的理解。

iterable是一个具有__iter__()方法的对象。它可以迭代多次,比如list()和tuple()。

迭代器是进行迭代的对象。它由__iter__()方法返回,通过自己的__iter__()方法返回自身,并有一个next()方法(3.x中的__next__())。

迭代是调用next()响应的过程。__next__()直到引发StopIteration。

例子:

>>> a = [1, 2, 3] # iterable
>>> b1 = iter(a) # iterator 1
>>> b2 = iter(a) # iterator 2, independent of b1
>>> next(b1)
1
>>> next(b1)
2
>>> next(b2) # start over, as it is the first call to b2
1
>>> next(b1)
3
>>> next(b1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> b1 = iter(a) # new one, start over
>>> next(b1)
1

Iterable:-可迭代的东西是可迭代的;比如序列,比如列表,字符串等等。 它也有__getitem__方法或__iter__方法。现在如果我们对该对象使用iter()函数,我们将得到一个迭代器。

迭代器:-当我们从iter()函数获得迭代器对象;我们调用__next__()方法(在python3中)或简单地调用next()(在python2中)来逐个获取元素。该类或该类的实例称为迭代器。

从文档:

迭代器的使用遍及并统一了Python。在后台,for语句在容器对象上调用iter()。该函数返回一个迭代器对象,该对象定义了__next__()方法,该方法每次访问容器中的一个元素。当没有更多的元素时,__next__()会引发一个StopIteration异常,告诉for循环终止。你可以使用next()内置函数调用__next__()方法;这个例子展示了它是如何工作的:

>>> s = 'abc'
>>> it = iter(s)
>>> it
<iterator object at 0x00A1DB50>
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
    next(it)
StopIteration

一个类的前:-

class Reverse:
    """Iterator for looping over a sequence backwards."""
    def __init__(self, data):
        self.data = data
        self.index = len(data)
    def __iter__(self):
        return self
    def __next__(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]


>>> rev = Reverse('spam')
>>> iter(rev)
<__main__.Reverse object at 0x00A1DB50>
>>> for char in rev:
...     print(char)
...
m
a
p
s

这是另一个使用collections.abc的视图。这个视图在第二次或以后可能会有用。

从集合。ABC我们可以看到下面的层次结构:

builtins.object
    Iterable
        Iterator
            Generator

例如,Generator是由Iterator派生的Iterable是由基对象派生的。

因此,

Every iterator is an iterable, but not every iterable is an iterator. For example, [1, 2, 3] and range(10) are iterables, but not iterators. x = iter([1, 2, 3]) is an iterator and an iterable. A similar relationship exists between Iterator and Generator. Calling iter() on an iterator or a generator returns itself. Thus, if it is an iterator, then iter(it) is it is True. Under the hood, a list comprehension like [2 * x for x in nums] or a for loop like for x in nums:, acts as though iter() is called on the iterable (nums) and then iterates over nums using that iterator. Hence, all of the following are functionally equivalent (with, say, nums=[1, 2, 3]): for x in nums: for x in iter(nums): for x in iter(iter(nums)): for x in iter(iter(iter(iter(iter(nums))))):

下面是我的小抄:

 sequence
  +
  |
  v
   def __getitem__(self, index: int):
  +    ...
  |    raise IndexError
  |
  |
  |              def __iter__(self):
  |             +     ...
  |             |     return <iterator>
  |             |
  |             |
  +--> or <-----+        def __next__(self):
       +        |       +    ...
       |        |       |    raise StopIteration
       v        |       |
    iterable    |       |
           +    |       |
           |    |       v
           |    +----> and +-------> iterator
           |                               ^
           v                               |
   iter(<iterable>) +----------------------+
                                           |
   def generator():                        |
  +    yield 1                             |
  |                 generator_expression +-+
  |                                        |
  +-> generator() +-> generator_iterator +-+

小测验:你看到…

每个迭代器都是可迭代对象? 容器对象的__iter__()方法可以实现为生成器? 具有__next__方法的迭代器不一定是迭代器?

答案:

Every iterator must have an __iter__ method. Having __iter__ is enough to be an iterable. Therefore every iterator is an iterable. When __iter__ is called it should return an iterator (return <iterator> in the diagram above). Calling a generator returns a generator iterator which is a type of iterator. class Iterable1: def __iter__(self): # a method (which is a function defined inside a class body) # calling iter() converts iterable (tuple) to iterator return iter((1,2,3)) class Iterable2: def __iter__(self): # a generator for i in (1, 2, 3): yield i class Iterable3: def __iter__(self): # with PEP 380 syntax yield from (1, 2, 3) # passes assert list(Iterable1()) == list(Iterable2()) == list(Iterable3()) == [1, 2, 3] Here is an example: class MyIterable: def __init__(self): self.n = 0 def __getitem__(self, index: int): return (1, 2, 3)[index] def __next__(self): n = self.n = self.n + 1 if n > 3: raise StopIteration return n # if you can iter it without raising a TypeError, then it's an iterable. iter(MyIterable()) # but obviously `MyIterable()` is not an iterator since it does not have # an `__iter__` method. from collections.abc import Iterator assert isinstance(MyIterable(), Iterator) # AssertionError