说我有一个项目列表,并且我想遍历其中的前几个:
items = list(range(10)) # I mean this to represent any kind of iterable.
limit = 5
来自其他语言的Python语言可能会编写以下完美可服务且性能卓越(如果是通用的)代码:
index = 0
for item in items: # Python's `for` loop is a for-each.
print(item) # or whatever function of that item.
index += 1
if index == limit:
break
但是Python已经枚举了,它很好地包含了大约一半的代码:
for index, item in enumerate(items):
print(item)
if index == limit: # There's gotta be a better way.
break
因此,我们已经将多余的代码减少了一半。但是必须有更好的方法。
我认为,如果枚举采用了另一个可选stop
参数(例如,它采用了start
这样的参数:)enumerate(items, start=1)
,那将是理想的选择,但以下内容不存在(请参见此处的枚举文档):
# hypothetical code, not implemented:
for _, item in enumerate(items, start=0, stop=limit): # `stop` not implemented
print(item)
请注意,index
由于无需引用它,因此无需命名。
是否有惯用的方式编写以上内容?怎么样?
第二个问题:为什么没有内置枚举?
如何限制Python中循环的迭代次数?
for index, item in enumerate(items): print(item) if index == limit: break
有没有一种简短,惯用的方式写上面的东西?怎么样?
zip
停止其参数的最短迭代。(与的行为相反zip_longest
,后者使用的是最长的可迭代对象。)
range
可以提供有限的可迭代项,我们可以将其与主要可迭代项一起传递给zip。
因此,我们可以将一个range
对象(带有其stop
参数)传递给它zip
并像使用有限枚举一样使用它。
zip(range(limit), items)
使用Python 3 zip
并range
返回可迭代对象,可迭代对象通过管道传递数据,而不是在中间步骤的列表中物化数据。
for index, item in zip(range(limit), items):
print(index, item)
为了获得在Python 2相同的行为,刚刚替补xrange
的range
和itertools.izip
为zip
。
from itertools import izip
for index, item in izip(xrange(limit), items):
print(item)
itertools.islice
您可以使用itertools.islice
:
for item in itertools.islice(items, 0, stop):
print(item)
不需要分配给索引。
enumerate(islice(items, stop))
获取索引正如Pablo Ruiz Ruiz指出的那样,我们也可以用枚举组成islice。
for index, item in enumerate(islice(items, limit)):
print(index, item)
为什么不内置
enumerate
?
这是用纯Python枚举实现的(可能进行了修改以在注释中获得所需的行为):
def enumerate(collection, start=0): # could add stop=None
i = start
it = iter(collection)
while 1: # could modify to `while i != stop:`
yield (i, next(it))
i += 1
对于已经使用枚举的人来说,上述方法的性能较差,因为它必须检查是否该停止每个迭代了。如果没有得到stop参数,我们可以检查并使用旧的枚举:
_enumerate = enumerate
def enumerate(collection, start=0, stop=None):
if stop is not None:
return zip(range(start, stop), collection)
return _enumerate(collection, start)
这种额外的检查对性能的影响可以忽略不计。
关于为什么枚举没有停止参数,这是最初提出的(请参阅PEP 279):
最初建议使用此函数以及可选的start和stop参数。GvR [Guido van Rossum]指出,该函数调用
enumerate(seqn, 4, 6)
具有一种替代的,合理的解释,即是一个片,该片将返回序列的第四和第五个元素。为了避免歧义,可选参数被删除,即使这意味着失去作为循环计数器的灵活性。对于从一个数开始计数的常见情况,这种灵活性最为重要,例如:for linenum, line in enumerate(source,1): print linenum, line
显然start
是因为它非常有价值而保留了它,而stop
因为它用例较少而被放弃了,并导致了对新功能使用的混淆。
另一个答案是:
为什么不简单使用
for item in items[:limit]: # or limit+1, depends
这里有一些缺点:
仅当您了解限制及其构成副本或视图时,才应使用带下标符号的切片。
我想现在Python社区知道枚举的用法,参数的值会超过混淆的代价。
在此之前,您可以使用:
for index, element in zip(range(limit), items):
...
要么
for index, item in enumerate(islice(items, limit)):
...
或者,如果您根本不需要索引:
for element in islice(items, 0, limit):
...
除非您了解这些限制,否则请避免使用下标符号进行切片。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句