Python:for循环 - for i in range(0,len(list)与for i in list之间的区别

8
这是一个非常简单的 Python 机制问题。为什么不能只说 "for i in range original_list" 而不是 "for i in range(0, len(original_list))"。人们通常使用 range 而不是前者吗?谢谢!
# "If I give you an array with negative and positive numbers (i.e. {3,2,-3,6,4,-7}) and asked you to sort it so that the negative numbers appeared first but you didn't change the relative order of the remaining numbers, how would you do it? (i.e. the final result would be {-3,-7,3,2,6,4}).

original_list = [3, 2, -3, 6, 4, -7]
pos_list = []
neg_list = []

for i in range(0, len(original_list)):
    if original_list[i] < 0:
        neg_list.append(original_list[i])
    else:
        pos_list.append(original_list[i])

print neg_list + pos_list
8个回答

14

在您的情况下,由于您不需要使用列表中的项目索引,因此您可以使用for in循环进行迭代:

>>> for item in original_list:
...     if item < 0:
...         ...

如果你想遍历列表中的索引,请使用for in range(..)

>>> for i in range(len(original_list)):
...     if original_list[i] < 0:
...         ...

如果您需要在循环体中同时获取元素和索引,您也可以使用enumerate()函数:

>>> for i, item in enumerate(original_list):
...    if item < 0:
...        ...

这样一来,您也可以避免使用original_list[i]


哪一个最有效率?这是情况而定的吗?我应该确保只有在需要两者时才使用enumerate吗? - Intrepid Diamond
标准写法是 for item in original_list - Matthias

7
构造函数 range(len(my_sequence)) 通常不被认为是 Python 中的惯用语。它会使你的代码专注于比我们通常尝试编写的更低级别的机制,这使得代码更难读懂。因此,在这里使用 range 大多被视为人们习惯于在像 C 这样的低级语言中编码的占位符。
例如,可以参考 Raymond Hettinger 的演讲 Transforming Code into Beautiful Idiomatic Python - 他建议的第一件事情就是将 for i in range(len(sequence)) 更改为 for item in sequence,无论它出现在哪里;然后,他继续提到了 enumeratezip 来覆盖那些你可能会倾向于回归使用 range 的情况。他还提到惯用方式更快。除了 Python 内置类型(毫不奇怪)被优化为快速运行惯用结构之外,很容易看出这对某些其他数据结构也适用 - 例如,链接列表可以比随机访问更快地进行顺序访问,这意味着依赖于 my_linked_list[i] 的循环可能会变成二次时间操作而不是线性时间操作。
如果你关注 [python] 标签的话,你也可以在 codereview.SE 上看到类似的建议。

2
如果您打开解释器并执行以下操作: help(range) 将会得到以下结果:
Help on built-in function range in module __builtin__:

range(...)
    range(stop) -> list of integers
    range(start, stop[, step]) -> list of integers

    Return a list containing an arithmetic progression of integers.
    range(i, j) returns [i, i+1, i+2, ..., j-1]; start (!) defaults to 0.
    When step is given, it specifies the increment (or decrement).
    For example, range(4) returns [0, 1, 2, 3].  The end point is omitted!
    These are exactly the valid indices for a list of 4 elements.

从描述中可以看出,这是范围的工作方式。它需要一个起始位置,然后是一个停止位置,最后是可选的步长以每次增加x。

编辑

根据您的评论回答,您之所以会得到索引超出范围的错误,是因为当您这样做时:

for i in arr:
    print(arr[i])

那样行不通,因为for i in arr会给你数组中每个项的。所以,你所做的实际上是将一个值放入arr中,就好像它是索引一样。但它不是。
当你这样做时: for i in range(0, len(arr)) 这里发生的是,你得到一个基于数组大小的递增值,这样你就可以将该值用作列表的索引。

我理解range的工作原理。我想知道的是,为什么使用for i in original_list运行代码时,与range(0,len(original_list))不会做相同的事情。如果我使用前者,它会抛出一个超出范围的异常。 - Intrepid Diamond

2

不要使用range来遍历值列表。请使用for item in list。如果需要索引,请使用enumerate。

for index, value in enumerate(original_list):
    print index
    print value

或者

for item in original_list:
    if item < 0:
        neg_list.append(item)
    else:
        pos_list.append(item)

您可能在使用for item in original_list:时出现了异常,因为您试图执行neg_list.append(original_list[item]),这可能会导致类似于original_list[-3]original_list[6]这样的超出范围的情况。


如果我尝试使用for item in list运行它,它会抛出一个超出范围的异常。你知道为什么吗? - Intrepid Diamond
所以,只是再次确认一下... http://puu.sh/kxR7Y/69a2c9924b.png,如果我只需要值,就使用方法1,如果我还需要索引,就使用enumerate/方法3? - Intrepid Diamond

2
lst=[1,2,3,4]

for i in range(lst):
    print lst[i]

你不能这样做。因为:

类型错误:range()整数结束参数应该是整数,得到了列表。

你可以做的是:

 for i in range(len(lst)): #i is the index here
     print lst[i]

输出: 1 2 3 4

或者,

 for i in lst: #i is the value here
     print i

输出:

1
2
3
4

实际上,在Python中,range并不是惯用语。你可以避免使用它。如果你需要索引,你可以像下面这样使用enumerate

 for i,j in enumerate(lst): #i is the index and j is the value here
 print i,j

希望现在你已经清楚了。

如果我只需要值,那么使用方法1;如果我还需要索引,那么使用enumerate/方法3? - Intrepid Diamond
如果您想通过 range() 访问 index,请使用方法1。如果不需要索引,请使用方法2。如果想要在不使用 range 的情况下获取 index,请使用方法3。 - Ahsanul Haque

0
我真的不知道为什么没有人写关于列表元素适用的文章。当你使用简单的for element in list并尝试在列表元素中写入一些信息时,它是无效的。只有当你使用元素的索引,例如list[0]="测试值",你才能重写它。

0

列表对象无法被解释为整数:

如果您想要操作列表项,那么您必须告诉编译器长度。

在另一种情况下,如果您想要直接使用range函数,请查看以下代码:

original_list = 3 for i in range(original_list): print("yes")

在上述情况中,没有len函数,因为我们使用的是单个整数,但是如果您使用列表、元组或集合,则必须使用len函数才能成功编译。


1
目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

0

itertools文档中有一个关于分区的配方:

def partition(pred, iterable):
    'Use a predicate to partition entries into false entries and true entries'
    # partition(is_odd, range(10)) --> 0 2 4 6 8   and  1 3 5 7 9
    t1, t2 = tee(iterable)
    return filterfalse(pred, t1), filter(pred, t2)

你可以像这样使用它:

positives, negatives = partition(lambda value: value < 0, originals)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接