在Python中,列表(list)和迭代器(iterator)的区别是什么?

28
我正在阅读的书籍是Think Python: How to think like a computer scientist,其中提到在Python 3.x中,dict([list of tuples])返回的是一个iterator而不是像Python 2.7一样返回一个list
该书没有进一步解释,这让我感到困惑。特别是,我想知道:
  1. 迭代器和列表有何不同?

  2. 返回迭代器相比于返回列表的优势是什么?


4
嗯...dict(...)返回一个dict。在两个Python版本中都是如此。你是指map吗? - roippi
6个回答

48

首先,你的书是错误的(或者你误解了它):

>>> dict([(1, 2), (3, 4), (5, 6)])
{1: 2, 3: 4, 5: 6}

正如你看到的,dict([元组列表]) 在Python 2.x和3.x中都会返回一个字典。

列表和迭代器之间的基本区别是,列表包含一定顺序的多个对象 - 因此你可以从中间取出其中一个对象:

>>> my_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> my_list
['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> my_list[3]
'd'

...而迭代器按特定顺序返回多个对象,通常根据需要即时创建它们:

>>> my_iter = iter(range(1000000000000))
>>> my_iter
<range_iterator object at 0x7fa291c22600>
>>> next(my_iter)
0
>>> next(my_iter)
1
>>> next(my_iter)
2

在这里我使用next()作为示范;在真实的代码中,使用for循环遍历迭代器更加普遍:

for x in my_iter:
    # do something with x

请注意权衡:一个由一万亿个整数组成的列表将使用比大多数机器可用空间更多的内存,这使得迭代器更加高效...但代价是无法在中间位置请求对象:

>>> my_iter[37104]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'range_iterator' object is not subscriptable

23

列表是一种数据结构,用于保存一系列值。迭代器是一个对象,通过next函数提供了逐个检索这些值的接口。

可迭代对象是指提供__iter__方法的对象,当将可迭代对象传递给iter函数时,该方法会被调用。通常不需要显式地执行此操作;例如,for循环会隐式地执行此操作。像下面这样的循环:

for x in [1,2,3]:
    print x

自动调用list__iter__方法。您也可以使用以下方式显式地调用:

for x in iter([1,2,3]):
    print x

或者更明确地说:

for x in [1,2,3].__iter__():
    print x

要看出它们之间的区别,一种方法是从一个列表中创建两个迭代器。

l = [1, 2, 3, 4, 5]
i1 = iter(l)
i2 = iter(l)
print next(i1)   # 1
print next(i1)   # 2
print next(i2)   # 1 again; i2 is separate from i1
print l          # [1, 2, 3, 4, 5]; l is unaffected by i1 or i2

1
iter()返回生成器吗?因为它支持next(),类似于生成器中的yield。 - variable
4
iter 返回一个迭代器。生成器只是迭代器的一种类型。查看 type(iter([1,2,3])) - chepner
我认为任何允许next()方法的东西内部都有一个yield,这是一个生成器。 - variable
2
这不正确。任何提供__next__(因此可以传递给next)的东西都是迭代器。可迭代对象是指提供__iter__(因此可以传递给iter)的东西。生成器只是一种迭代器,由使用yield的可调用对象创建,但并非所有迭代器都是使用yield创建的。 - chepner

5

迭代器是一种机制,可以使用 for 迭代列表或其他集合对象/值。 列表实现了一个迭代器。 但是,您也可以实现返回数字序列、随机字符串等的迭代器。

当您返回一个迭代器时,您只是返回迭代对象;接收代码不知道底层容器或生成算法的任何信息。

迭代器是惰性的;只有在被要求时才返回序列或列表中的下一个元素。 因此,您可以使用它们来实现无限序列。

进一步阅读
迭代器类型
for 语句


5
这里的关键定义如下:
  • List(列表): 完全存储在内存中,并且它也是一个迭代器——即您可以从一个元素移动到下一个元素。
  • Iterable(可迭代对象):任何实现迭代器协议的对象——即允许您从一个元素移动到下一个元素。它可以使用存储在内存中的数据,也可以是文件,或者每一步都可以计算出来。

许多东西都是可迭代的,但并非所有可迭代的东西都是列表。


2

迭代器是一种产生值的对象,但不一定与包含所有要产生的值的内存数据结构相关联。相比之下,列表完全构建并驻留在内存中。基本上,迭代器通常比作为内存结构创建的相同数据更具有内存效率,并且通常更具有性能,因为所有每个元素的计算可以在访问该元素时完成,而不是预先加载,并且不需要将所有元素驻留在内存中。


iter()返回一个生成器吗? - variable

1

您应该阅读Python文档中关于迭代器协议的指南,可以在此处找到:https://docs.python.org/2/library/stdtypes.html#iterator-types

基本上,在Python中,迭代器是符合通用协议的那些用于在容器中迭代元素的对象。一个list是符合该协议的特定容器类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接