是否需要范围(len(a))?

经常在SO上的python问题中find这种types的expression式。 要么只是访问迭代的所有项目

for i in range(len(a)): print(a[i]) 

这只是一个笨拙的写作方式:

 for e in a: print(e) 

或者分配给迭代元素:

 for i in range(len(a)): a[i] = a[i] * 2 

这应该是一样的:

 for i, e in enumerate(a): a[i] = e * 2 # Or if it isn't too expensive to create a new iterable a = [e * 2 for e in a] 

或者用于筛选索引:

 for i in range(len(a)): if i % 2 == 1: continue print(a[i]) 

可以这样expression:

 for e in a [::2]: print(e) 

或者当你只需要列表的长度,而不是它的内容:

 for _ in range(len(a)): doSomethingUnrelatedToA() 

这可能是:

 for _ in a: doSomethingUnrelatedToA() 

在python中,我们enumerate ,切片, filtersorted等等…由于python for构造是为了遍历iterables而不是只有整数的范围,有真实世界的用例,你需要in range(len(a))

如果你需要使用序列索引,那么是的 – 你使用它…例如numpy.argsort的等价物:

 >>> a = [6, 3, 1, 2, 5, 4] >>> sorted(range(len(a)), key=a.__getitem__) [2, 3, 1, 5, 4, 0] 

简单的回答 :math上来说,不,实际上,是的,例如有意编程。

从技术上讲,我认为math上正确的答案是“不,这是不需要的”,因为它可以用其他构造来expression,也就是说,它等价于其他构造……就像一个语言是图灵完整的, /范式结构,因为无论如何,一切都可以expression出来。

但是在实践中,如果我不需要索引,我将它for i in range(len(a) (或for _ in range(len(a)) )中,使其明确表示我想迭代多次是序列中的项目,而不需要按顺序使用任何项目中的项目。

所以要回答“有需要吗?” 部分 – 我需要为了可读性目的来expression代码的含义/意图。

另见: https : //en.wikipedia.org/wiki/Intentional_programming

PS,但同时,从意图编程的angular度来看,以下似乎在语义上是等价的:

 for _ in a: ... 

要么

 b = ["hello" for _ in a] 

…总而言之,我猜想不同之处在于,你是否真的需要对“重复多次,因为a中有项目”而不是“a中的每个元素,而不pipea的内容” 。这只是一个故意编程的细微差别。

根据评论和个人经验,我说不, range(len(a))是没有必要range(len(a)) 。 你可以用range(len(a))做的所有事情都可以用另一种方式来完成(通常效率更高)。

你在post中给了很多例子,所以我不会在这里重复。 相反,我会给那些说“如果我只想要一个长度而不是项目?”的人举个例子。 这是您可能考虑使用range(len(a))的唯一时间之一。 但是,即使这样做也可以这样做:

 >>> a = [1, 2, 3, 4] >>> for _ in a: ... print True ... True True True True >>> 

克莱门茨的回答(如Allik所示)也可以重写以去除range(len(a))

 >>> a = [6, 3, 1, 2, 5, 4] >>> sorted(range(len(a)), key=a.__getitem__) [2, 3, 1, 5, 4, 0] >>> # Note however that, in this case, range(len(a)) is more efficient. >>> [x for x, _ in sorted(enumerate(a), key=lambda i: i[1])] [2, 3, 1, 5, 4, 0] >>> 

所以,总之, range(len(a))不需要的 。 它唯一的好处是可读性(它的意图是明确的)。 但是,这只是偏好和代码风格。

我有一个用例,我不相信你的任何例子。

 boxes = [b1, b2, b3] items = [i1, i2, i3, i4, i5] for j in range(len(boxes)): boxes[j].putitemin(items[j]) 

我相对较新的python,虽然很高兴学习一个更优雅的方法。

如果你需要同时访问列表中的两个元素呢?

 for i in range(len(a[0:-1])): something_new[i] = a[i] * a[i+1] 

你可以使用这个,但可能不太清楚:

 for i, _ in enumerate(a[0:-1]): something_new[i] = a[i] * a[i+1] 

我个人并不是100%满意!

有时matplotlib需要range(len(y)) ,例如,当y=array([1,2,5,6])plot(y)工作正常, scatter(y)不会。 必须写scatter(range(len(y)),y) 。 (就我个人而言,我认为这是一个scatter的错误; plot和它的朋友scatterstem应尽可能使用相同的调用序列。)

当你需要使用索引进行某种操作并使当前元素不够用的时候,很好。 拿一个二进制树存储在一个数组中。 如果你有一个方法要求你返回包含每个节点的元组列表,那么你需要索引。

 #0 -> 1,2 : 1 -> 3,4 : 2 -> 5,6 : 3 -> 7,8 ... nodes = [0,1,2,3,4,5,6,7,8,9,10] children = [] for i in range(len(nodes)): leftNode = None rightNode = None if i*2 + 1 < len(nodes): leftNode = nodes[i*2 + 1] if i*2 + 2 < len(nodes): rightNode = nodes[i*2 + 2] children.append((leftNode,rightNode)) return children 

当然,如果你正在处理的元素是一个对象,你可以调用一个get儿童方法。 但是,如果你正在做某种操作,你只需要索引。

很简单的例子:

 def loadById(self, id): if id in range(len(self.itemList)): self.load(self.itemList[id]) 

我想不出一个不能很快使用range-len组合的解决scheme。

但可能相反,这应该做的try .. except留pythonic我猜..

如果必须迭代对象b (大于a )的第一个len(a)项,则应该使用range(len(a))

 for i in range(len(a)): do_something_with(b[i]) 

有时候,你真的不关心collections本身 。 例如,创build一个简单的模型拟合线来比较“逼近”与原始数据:

 fib_raw = [1, 1, 2, 3, 5, 8, 13, 21] # Fibonacci numbers phi = (1 + sqrt(5)) / 2 phi2 = (1 - sqrt(5)) / 2 def fib_approx(n): return (phi**n - phi2**n) / sqrt(5) x = range(len(data)) y = [fib_approx(n) for n in x] # Now plot to compare fib_raw and y # Compare error, etc 

在这种情况下,斐波纳契数列本身的值是不相关的。 我们所需要的只是我们比较的input序列的大小。