混乱于Python列表:它们是迭代器还是不是迭代器?
混乱于Python列表:它们是迭代器还是不是迭代器?
我正在学习《Python速查手册》(Alex Marteli著),这本书提到任何具有next()
方法的对象都是(或至少可以被用作)迭代器。书中还提到,大多数迭代器都是通过隐式或显式调用一个名为iter
的方法来构建的。
在读到这段内容后,我有一种尝试的冲动。我打开了一个Python 2.7.3解释器,并进行了如下操作:
>>> x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> for number in range(0, 10): ... print x.next()
然而结果是这样的:
Traceback (most recent call last): File "", line 2, in AttributeError: 'list' object has no attribute 'next'
混淆不解之际,我尝试通过dir(x)
来研究x对象的结构,我注意到它有一个__iter__
函数对象。所以我想出来了一个办法,只要它支持这种类型的接口,它就可以被用作一个迭代器。
所以当我再次尝试时,这次稍微有些不同,试图做到这一点:
>>> _temp_iter = next(x)
我得到了这个错误:
Traceback (most recent call last): File "", line 1, in TypeError: list object is not an iterator
但是一个列表怎么可能不是一个迭代器呢?因为它看起来支持这个接口,并且在以下上下文中肯定可以被用作一个迭代器:
>>> for number in x: ... print x
有人能帮我澄清一下这个问题吗?
Python中的列表是可迭代对象(iterable),可以通过使用迭代器(iterator)来对列表进行多次遍历。迭代器是一种表示数据流的对象,它实现了迭代器协议(iterator protocol),包括`__iter__`方法和`next`方法。通过多次调用迭代器的`next()`方法,可以依次返回数据流中的每个元素。当没有更多的数据可用时,迭代器对象将耗尽,并且对其`next()`方法的进一步调用将引发StopIteration异常。
相反,可迭代对象实现了`__iter__`方法,当调用该方法时,返回一个迭代器,允许对其数据进行多次遍历。可迭代对象是可重复使用的,一旦耗尽,可以再次进行迭代。可以使用`iter`函数将可迭代对象转换为迭代器。
如果你有一个列表(可迭代对象),你可以这样做:
l = [1, 2, 3, 4] for i in l: print(i, end=' ') # 输出:1 2 3 4 for i in l: print(i, end=' ') # 输出:1 2 3 4
如果将列表转换为迭代器:
il = l.__iter__() # 等同于 iter(l) for i in il: print(i, end=' ') # 输出:1 2 3 4 for i in il: print(i, end=' ') # 没有输出
出现混淆的原因是,当使用迭代器对列表进行遍历后,再次使用同一个迭代器进行遍历时,并没有输出任何结果。这是因为迭代器对象已经耗尽,再次调用其`next()`方法时并没有可用的数据。
解决这个问题的方法是重新创建一个迭代器对象,或者将列表转换为可迭代对象再进行遍历。
il = iter(l) # 创建新的迭代器对象 for i in il: print(i, end=' ') # 输出:1 2 3 4 for i in il: print(i, end=' ') # 输出:1 2 3 4
或者直接使用可迭代对象进行遍历:
l = [1, 2, 3, 4] for i in l: print(i, end=' ') # 输出:1 2 3 4 for i in l: print(i, end=' ') # 输出:1 2 3 4
通过理解列表作为可迭代对象和迭代器之间的区别,以及如何正确使用它们,可以避免对列表遍历时出现的混淆。
在Python中,列表(list)和迭代器(iterator)是两个不同的概念。列表是一种可迭代对象(iterable),而迭代器是可迭代对象的一个特殊实例。
上述代码中的问题是对列表进行迭代时出现的。在使用for循环迭代列表时,会发现不能使用列表的next()方法。为了解决这个问题,需要将列表转换为迭代器,可以使用iter()函数来实现转换。通过将列表传递给iter()函数,可以得到一个迭代器对象。
下面是解决这个问题的代码片段:
x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] it = iter(x) for i in range(10): it.next()
在这个例子中,先将列表x转换为迭代器it,然后通过for循环迭代该迭代器。通过调用next()方法,可以获取迭代器的下一个元素。
另外,可以使用isinstance()函数来检查一个对象是否是迭代器或可迭代对象。在上述代码中,使用isinstance()函数检查列表和迭代器的类型。可以看到,列表是可迭代对象,而迭代器既是可迭代对象也是迭代器。
下面是检查对象是否为迭代器或可迭代对象的代码片段:
import collections isinstance(x, collections.Iterator) # 检查x是否是迭代器 isinstance(x, collections.Iterable) # 检查x是否是可迭代对象 isinstance(it, collections.Iterable) # 检查it是否是可迭代对象 isinstance(it, collections.Iterator) # 检查it是否是迭代器
通过使用isinstance()函数,可以确定一个对象的类型是否符合预期。
列表和迭代器是两个不同的概念。在使用for循环迭代列表时,需要先将列表转换为迭代器。通过使用iter()函数将列表转换为迭代器对象,可以解决这个问题。同时,使用isinstance()函数可以检查一个对象是否是迭代器或可迭代对象。
在Python中,列表(list)是可迭代的(iterable),但它们本身不是迭代器(iterator)。可以通过将列表传递给iter()函数来隐式或显式地获取迭代器(iterator),但它们本身并不是迭代器。
需要注意的是,所有的迭代器(well-behaved)都是可迭代的,它们的next方法只是返回self,因此可以调用iter(iter(iter(iter(x))))并得到与iter(x)相同的结果。这就是为什么for循环既可以用于可迭代对象(iterables)也可以用于迭代器(iterators),而无需类型检查(忽略性能优化)。
为什么设计成可迭代对象(iterables)不是迭代器(iterators)呢?因为迭代器不支持随机访问。
关于列表类(list)的实现,虽然list类的定义中没有明确继承可迭代对象,但实际上它是可迭代的。这是因为Python在实现列表类时,内部实现了__iter__方法,该方法返回一个迭代器对象。所以虽然列表类没有直接继承可迭代对象,但它仍然可以被视为可迭代的对象。
总结一下,Python的列表是可迭代的,但不是迭代器。它们可以通过iter()函数获取迭代器。列表类虽然没有直接继承可迭代对象,但实际上它是可迭代的,因为它实现了__iter__方法返回一个迭代器对象。