你的标题中提出的问题的答案,“哪个更pythonic;压缩或枚举......?”是:他们都是。 enumerate 只是 zip 的一个特例。
关于那个for循环的更具体问题的答案是:使用zip,但不是因为你目前看到的原因。
zip 在那个循环中的最大优势与zip 本身无关。这与避免在enumerate 循环中所做的假设有关。为了解释,我将根据您的两个示例制作两个不同的生成器:
def process_items_and_tags(items, tags):
"Do something with two iterables: items and tags."
for item, tag in zip(items, tag):
yield process(item, tag)
def process_items_and_list_of_tags(items, tags_list):
"Do something with an iterable of items and an indexable collection of tags."
for idx, item in enumerate(items):
yield process(item, tags_list[idx])
两个生成器都可以将任何可迭代对象作为它们的第一个参数 (items),但它们处理第二个参数的方式不同。 基于enumerate 的方法只能处理带有[] 索引的list 类集合中的标签。这无缘无故地排除了大量的可迭代对象,例如文件流和生成器。
为什么一个参数的约束比另一个参数更严格?限制不是用户试图解决的问题所固有的,因为生成器可以很容易地以相反的方式编写:
def process_list_of_items_and_tags(items_list, tags):
"Do something with an indexable collection of items and an iterable of tags."
for idx, tag in enumerate(tags):
yield process(items[idx], tag)
相同的结果,不同的输入限制。为什么您的来电者必须知道或关心这些?
作为附加惩罚,some_list[some_index] 形式的任何内容都可能引发IndexError,您必须以某种方式捕获或阻止它。当您的循环同时枚举和访问同一个类似列表的集合时,这通常不是问题,但在这里您是在枚举一个然后从另一个访问项目。您必须添加更多代码来处理在基于zip的版本中不可能发生的错误。
避免不必要的idx 变量也不错,但几乎不是这两种方法之间的决定性区别。
有关可迭代对象、生成器和使用它们的函数的更多信息,请参阅 Ned Batchelder 的 PyCon US 2013 演讲“Loop Like a Native”(text、30-minute video)。