假如我们要迭代两个列表,如下:
names = ['Cecilia', 'Lise', 'Marie'] counts = [len(n) for n in names] print(counts) # [7, 4, 5]
下面我们来迭代这两份列表,根据长度迭代:
longset_name = None
max_count = 0
for i in range(len(names)):
count = counts[i]
if count > max_count:
longset_name = names[i]
max_count = count
print(longset_name) # Cecilia
上面整个循环比较乱,是通过下标names和counts这两个列表里的元素。下面改用enumerate实现,但是仍然不理想:
for i, name in enumerate(names):
count = counts[i]
if count > max_count:
longset_name = name
max_count = count
下面通过zip函数实现,可以是代码个让你更加简洁:
for name, count in zip(names, counts):
if count > max_count:
longset_name = name
max_count = count
zip函数能把两个或更多的iterator封装成惰性生成器(lazy generator)。每次循环,从各个迭代器获取各自的下一个元素,并放在一个数组里。然后元素可以拆分for循环的那些变量中。
zip函数还有个好处就是每次从哪些迭代器里各自取一个元素,即使源列表很长,程序也不会因占用内存过多而崩溃。
但是,当zip函数里面的长度不一致了,会怎么样呢?,如下,names列表增加一个元素再遍历:
names.append('Rose')
for name, count in zip(names, counts):
print(f'{name}: {count}')
# Cecilia: 7
# Lise: 4
# Marie: 5
可以看到新加的名字并没有打印出来。因为zip函数这样设计的:只有其中一个迭代器处理完毕,就不会往下走了,所以循环的次数实际是最短的列表的长度。
所以,一般不一样长的列表,就不要使用zip函数了。可以使用另外一个zip_longest函数,这个函数位于内置的iterator模块里。
import itertools
for name, count in itertools.zip_longest(names, counts):
print(f'{name}: {count}')
# Cecilia: 7
# Lise: 4
# Marie: 5
# Rose: None
当其中有些列表走完了,那么会填充默认值None。
要点
- 内置的zip函数可以同时遍历多个迭代器
- zip会创建惰性生成器,每次值生成一个元组,减少内存占用
- 如果迭代器程度不一致,其中一个迭代完毕后,zip会自动停止
- 如果想按照长度长的来遍历,那就改内置的itertools模块的zip_longest函数



