iter() 对列表没有任何作用; list 对象有一个 __iter__ 方法,iter() 使用它来生成一个迭代器对象。该对象具有对原始列表的引用和索引;每次在迭代器中请求下一个值时,都会检索并返回当前索引处的值,并增加索引。
您可以使用next() 函数从迭代器中获取下一个值:
>>> a = ['animal', 'dog', 'car', 'bmw', 'color', 'blue']
>>> a_iter = iter(a)
>>> next(a_iter) # get the next value
'animal'
>>> next(a_iter) # get the next value
'dog'
请注意再次调用next() 会给您带来新的价值。您可以这样做直到迭代器完成:
>>> three_more = next(a_iter), next(a_iter), next(a_iter)
>>> next(a_iter) # last one
'blue'
>>> next(a_iter) # nothing left
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
列表迭代器对象保留原始列表对象;更改列表对象将反映在 next() 上生成的迭代器值:
>>> b = ['foo', 'bar']
>>> b_iter = iter(b)
>>> next(b_iter)
'foo'
>>> b[1] = 'spam'
>>> b
['foo', 'spam']
>>> next(b_iter)
'spam'
zip() 要求其每个参数中的下一个值,假定为 iterables; zip() 给他们打电话iter()。对于a_iter等迭代器对象,iter(a_iter)返回迭代器本身(毕竟它已经是一个迭代器了):
>>> iter(a_iter)
<list_iterator object at 0x10e7b6a20>
>>> iter(a_iter) is a_iter
True
由于a_iter 将按顺序从原始列表中产生值,这意味着您会在字典中获得成对的元素,因为zip() 有对同一个对象的两个引用;您有效地将(next(a_iter), next(a_iter)) 创建为zip() 的迭代器步长值。另一方面,如果您传入两个对a 的引用,zip() 将调用iter()两次,创建两个单独的迭代器对象,每个迭代器对象都有自己的自己要跟踪的索引。
让我们详细了解一下。注意zip()也产生了一个迭代器对象,所以我们可以验证在zip()上调用next()反过来会导致a_iter前进两次:
>>> a_iter = iter(a)
>>> a_iter_zip = zip(a_iter, a_iter)
>>> a_iter_zip # a zip object is an iterator too
<zip object at 0x10e7ba8c8>
>>> next(a_iter_zip) # get next value of a_iter, together with the next value of a_iter
('animal', 'dog')
>>> next(a_iter) # the a-list iterator was advanced, so now we get 'car'
'car'
>>> next(a_iter_zip) # now a_iter is at bmw, so we get bmw and color
('bmw', 'color')
迭代器是独立的对象,它们都有自己的索引:
>>> a_iter1 = iter(a)
>>> a_iter2 = iter(a) # different iterator from a_iter1
>>> next(a_iter1), next(a_iter1) # what zip() does
('animal', 'dog')
>>> next(a_iter2), next(a_iter2) # iter2 is independent
('animal', 'dog')
所以当你使用zip(a, a) 时,真正发生的是zip() 调用iter(a) 两次,创建了两个新的迭代器,并且都用于创建输出:
>>> a_iter1 = iter(a)
>>> a_iter2 = iter(a)
>>> a_iter_1_and_2_zip = zip(a_iter1, a_iter2)
>>> next(a_iter_1_and_2_zip) # values from a_iter1 and a_iter2
('animal', 'animal')
>>> next(a_iter_1_and_2_zip) # moving in lockstep
('dog', 'dog')
>>> next(a_iter1) # moving one of these two one step along, to 'car'
'car'
>>> next(a_iter_1_and_2_zip) # so a_iter1 is one step ahead!
('bmw', 'car')
>>> next(a_iter1) # another extra step
'color'
>>> next(a_iter_1_and_2_zip) # so a_iter1 is two steps ahead!
('blue', 'bmw')