在python中迭代和更新列表

kum*_*mo2 4 python for-loop list python-2.x python-3.x

我无法理解为什么以下代码无限循环(当我不使用副本列表时)

list = ["Mohit","kumar","sffsfshfsd"]
for w in list:
    if(len(w)) > 5:
        list.insert(0,w)
    print("inside loop")

print(list)  
Run Code Online (Sandbox Code Playgroud)

上面的代码无限期地打印在循环内部.

现在,如果代替列表,我使用下面的副本列表工作正常.

list = ["mohit","kumar","sffffgssddf"]

for w in list[:]:
    if len(w) > 5:
        list.insert(0,w)
    print("inside loop")

print(list)  
Run Code Online (Sandbox Code Playgroud)

现在我已经在python文档中读到这是我将得到的行为,但我想了解它背后的原因.提前致谢.

Bil*_*kil 5

第一个for循环for w in list将使用迭代器(from iter(list))来检索和循环列表中的每个项目.这个迭代器不会立即获取整个列表 - 它是懒惰的,这意味着它只需要一次从列表中获取一个项目.您可以在这里了解 迭代协议,或迭代/生成器和懒惰.

循环索引0和1不执行任何操作,因为它们的字符串长度小于6.但是,在索引2处,您将添加"sffsfshfsd"到开头list.现在list已经增长,并且在索引3处有一些东西:"sffsfshfsd".然后迭代继续,选择从下一个索引(3),其被再次在开始添加,移动这是在指数3至4索引值相同的值...循环永远不会结束.

在第二个循环中,w in list[:]您将创建整个列表的副本(通过使用切片运算符)并迭代它.您要将项目添加到原始列表,而不是副本,因此迭代器不会触及您添加的项目.

PS:我试图搜索Python源代码(即C)来证明列表迭代器实际上使用递增索引(如上所述).我不太熟悉Python的源代码,但这是我在cpython/listobject.c中找到的:

迭代器创建,将起始索引设置为0

2797 static PyObject *
2798 list_iter(PyObject *seq)
2799 {
....
2806     it = PyObject_GC_New(listiterobject, &PyListIter_Type);
....
2809     it->it_index = 0;
....
2813     return (PyObject *)it;
2814 }
Run Code Online (Sandbox Code Playgroud)

nextit->it_index从上面使用然后递增它

2831 static PyObject *
2832 listiter_next(listiterobject *it)
2833 {
....
2844         item = PyList_GET_ITEM(seq, it->it_index);
2845         ++it->it_index;
....
2847         return item;
....
2853 }
Run Code Online (Sandbox Code Playgroud)

对我来说似乎合法吗?