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.
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?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With