zip()函数最早出现在Python 2(当时返回一个列表),从Python 3开始返回惰性迭代器。它按元素将多个序列“拉链”在一起,便于有效地处理并行可迭代集合。
通常需要同时处理多个列表(或其他类型的序列)——例如遍历键值对或处理点对的坐标。独立同步索引会导致错误和代码的可读性下降,尤其是对于不同长度的集合。
zip()函数接受任意数量的可迭代对象,并返回一个元组迭代器,每个元组中包含对应的可迭代对象的元素。如果序列长度不同,结果将在最短的地方中断。
names = ['Alice', 'Bob', 'Charlie'] ages = [24, 27, 30] for name, age in zip(names, ages): print(f'{name} is {age} years old')
可以使用*展开zip:
pairs = [(1, 'a'), (2, 'b'), (3, 'c')] nums, chars = zip(*pairs) print(nums) # (1, 2, 3) print(chars) # ('a', 'b', 'c')
如果将不同长度的集合传递给zip()会发生什么?
zip()会在到达最短集合的末尾时停止——其他较长集合的元素会被忽略。
print(list(zip([1,2,3], ['a','b']))) # [(1, 'a'), (2, 'b')]
如何得到元组,补充较短的序列为默认值?
标准的zip()不会这样做,但可以使用itertools.zip_longest实现此行为:
from itertools import zip_longest for a, b in zip_longest([1,2], ['x','y','z'], fillvalue=None): print(a, b) # 1 x # 2 y # None z
可以“解包”zip()的结果以重新获得原始列表吗?
可以,如果所有原始集合的长度相同且结果未被修改,操作符*可以展开zip。
pairs = [(1,2), (3,4)] a, b = zip(*pairs) print(a) # (1, 3) print(b) # (2, 4)
处理不同长度的关联集合而不考虑zip的特性:
lst1 = [1,2,3,4] lst2 = ['a','b'] for x, y in zip(lst1, lst2): print(x, y) # 1 a # 2 b # (3,4)和'l','c'没有被处理
优点:
缺点:
使用zip_longest与fillvalue,以确保不丢失任何元素:
from itertools import zip_longest lst1 = [1,2,3,4] lst2 = ['a','b'] for x, y in zip_longest(lst1, lst2, fillvalue='?'): print(x, y) # 1 a # 2 b # 3 ? # 4 ?
优点:
缺点: