几乎每个关于这个主题的教程和SO答案都坚持你在迭代它时不应该修改列表,但是如果代码有效,我不明白为什么这是一件坏事.例如:
while len(mylist) > 0:
print mylist.pop()
Run Code Online (Sandbox Code Playgroud)
我错过了什么吗?
eum*_*iro 13
while len(mylist) > 0:
print mylist.pop()
Run Code Online (Sandbox Code Playgroud)
你没有迭代列表.你每次都在检查原子状况.
也:
while len(mylist) > 0:
Run Code Online (Sandbox Code Playgroud)
可以改写为:
while len(mylist):
Run Code Online (Sandbox Code Playgroud)
可以改写为:
while mylist:
Run Code Online (Sandbox Code Playgroud)
为什么你不应该在迭代时修改列表的原因是,例如,你正在迭代20个数字的列表,如果你点击偶数,你将它从列表中弹出并继续直到你有一个列表奇怪的数字.
现在,假设这是您的示例数据[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],并开始迭代它.第一次迭代,数字是1这样你继续,下面的数字是2这样你把它弹出,然后冲洗并重复.您现在感觉应用程序正常工作,因为结果列表是[1, 3, 5, 7, 9, 11, 13, 15, 17, 19].
现在让我们假设您的示例数据是,[1, 2, 4, 5, 7, 8, 10, 11, 12, 13, 15, 15, 17, 18, 20]并且您运行与以前相同的代码片段,并在迭代原始列表的同时改变原始列表.您的结果列表[1, 4, 5, 7, 10, 11, 13, 15, 15, 17, 20]显然不正确,因为列表中仍包含偶数.
如果你打算改变列表,同时迭代它
for elem in lst:
# mutate list in place
Run Code Online (Sandbox Code Playgroud)
你应该把它改成
for elem in lst[:]:
# mutate list in place
Run Code Online (Sandbox Code Playgroud)
该[:]语法创建一个新的列表,它是原始表的精确副本,让您可以愉快地变异原始列表,而不会影响你正在处理什么,你不会有突变,从你的列表中的任何意外的副作用迭代.
如果您的列表相当大,而不是创建一个新列表并单步执行它,请查看使用生成器表达式,或者如果您觉得有必要,请为列表编写自己的生成器,以免浪费内存和CPU周期.
我将详细介绍为什么不应该迭代列表.当然,我的意思是
for elt in my_list:
my_list.pop()
Run Code Online (Sandbox Code Playgroud)
或类似的习语.
首先,我们需要考虑Python的for循环.由于您可以尝试迭代任何对象,因此Python不一定知道如何迭代您提供的任何对象.因此,有一个列表(heh)它试图解决如何逐个呈现值的事情.它首先要做的是检查__iter__对象上的方法,如果存在,则调用它.
这个调用的结果将是一个可迭代的对象; 也就是说,一个next方法.现在我们很高兴:只是next反复打电话直到StopIteration被提出.
为什么这很重要?好吧,因为该__iter__方法实际上要查看数据结构以查找值,并记住一些内部状态,以便它知道下一步要查看的位置.但是如果你改变数据结构然后__iter__无法知道你一直在摆弄,那么它将继续尝试抓住新数据.这在实践中意味着您可能会跳过列表中的元素.
通过查看源代码来证明这种说法是很好的.来自listobject.c:
static PyObject *
listiter_next(listiterobject *it)
{
PyListObject *seq;
PyObject *item;
assert(it != NULL);
seq = it->it_seq;
if (seq == NULL)
return NULL;
assert(PyList_Check(seq));
if (it->it_index < PyList_GET_SIZE(seq)) {
item = PyList_GET_ITEM(seq, it->it_index);
++it->it_index;
Py_INCREF(item);
return item;
}
Py_DECREF(seq);
it->it_seq = NULL;
return NULL;
}
Run Code Online (Sandbox Code Playgroud)
特别要注意的是,它确实模拟了C风格的for循环,并且it->it_index扮演了索引变量的一部分.特别是,如果从列表中删除项目,则不会更新it_index,因此您可以跳过某个值.
| 归档时间: |
|
| 查看次数: |
5444 次 |
| 最近记录: |