Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterating and Updating the list in python [duplicate]

I am not able to understand why the following code goes in indefinite loop(when i am not using the copy list)

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

print(list)  

The Above code prints inside loop indefinitely.

Now if in place of the list, i use a copy list like below works fine.

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

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

print(list)  

Now i have read in the python documentation that this is the behavior i will get but i want to understand the reason behind it. Thanks in advance.

like image 248
kumarmo2 Avatar asked Dec 03 '22 21:12

kumarmo2


1 Answers

The first for loop for w in list will use an iterator (from iter(list)) to retrieve and loop through each item in the list. This iterator does not fetch the entire list immediately - it is lazy, meaning it only gets one item at a time from the list, when it's needed. You can learn about the iteration protocol here, or iteration/generators and laziness here.

Looping through indexes 0 and 1 do nothing, as their string lengths are less than 6. At index 2, however, you add "sffsfshfsd" to the beginning of list. Now list has grown and there's something at index 3: "sffsfshfsd". Iteration then continues, picking the value from the next index (3), which gets added at the beginning again, moving the same value which was at index 3 to index 4... The cycle never ends.

In your second loop w in list[:] you create a copy of the entire list (by using a slice operator) and iterate through that. You're adding items to the original list, not the copy, so the iterator won't touch the items that you've added.

PS: I tried to search the Python source code (which is C) to prove that list iterators in fact use an incrementing index (as described above). I'm not well versed in reading Python's source code, but here's what I found in cpython/listobject.c:

Iterator creation, sets starting index to 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 }

next uses it->it_index from above and then increments it

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 }

Seems legit to me?

like image 64
Bilal Akil Avatar answered Dec 27 '22 16:12

Bilal Akil