将迭代器转换为列表会更改迭代器

时间:2016-03-18 21:45:58

标签: python list iterator

以下代码会产生一些非常奇怪的结果

import re
string = "test test test"
positions = re.finditer("test", string)
print (list(positions))
print (list(positions))

输出:

[<Match object...>, <Match object...>, <Match object...>]
[]

现在,我想我知道这里发生了什么。第一次list电话&#34;耗尽&#34;迭代器(所以它&#34;使用迭代器和#34;,就像在生成器中一样,在从迭代器创建列表的过程中),然后当第二次调用list时,迭代器消失了,我们得到一个空列表。这似乎可以通过下面的段落得到证实,虽然我正在尝试理解他们在这里所说的一些事情,所以我对这个解释并不完全满意(如果它是正确的):

  

容器对象(例如列表)会生成一个全新的迭代器   每次将它传递给iter()函数或在for循环中使用它。   尝试使用迭代器只会返回相同的耗尽   在上一次迭代过程中使用的迭代器对象,使其出现   就像一个空容器。

以上段落来自the official documentation

我真的不明白他们在上一段的第一句话中说了什么,特别是关于传递给iter()函数,我不知道他们如何将for循环中的用法连接到列表生成一个新的迭代器。但是,第二句似乎更接近我上面的代码中我最初的想法。

如果有人能帮我解决这里的困惑,我会非常感激。

注意:

我正在使用Python 3.5.1

2 个答案:

答案 0 :(得分:1)

这一行:

positions = re.finditer("test", string)

It returns a one-shot iterator。然后你在同一个迭代器上调用了list(positions) 两次

所以对于第二次通话,它已经用尽了。

列表会在每次迭代时为您提供一个新的迭代器,因此列表本身没有令人筋疲力尽的行为。比较下面的行为,以了解您引用的文档:

>>> L = ['a', 'b', 'c']
>>> list(L)
['a', 'b', 'c']
>>> list(L)
['a', 'b', 'c']
>>> iter_L = iter(L)  # calls L.__iter__() and returns you a one-shot iterator
>>> list(iter_L)
['a', 'b', 'c']
>>> list(iter_L)
[]

答案 1 :(得分:0)

当list()在迭代器上运行时,它基本上会调用next(),直到它引发异常StopIteration,然后将next()返回的每个东西追加到列表中,然后返回该列表。基本上,list(iter)的实现可能是:

my_list(iter):
    output = []
    try:
        while True:
            output.append(iter.next())
    except StopIteration:
        return output

顺便说一下,for循环完全相同,但它不是output.append(iter.next())而是循环体。