0

I am just learning Python and in the documentation the below example is mentioned and they have not mentioned the reason for this behavior.

words = ['cat', 'window', 'defenestrate']
for w in words[:]:
    if(len(w) > 6):
       words.insert(0,w)

From what I understand the above would iterate over the elements by first creating a copy of the original array and the syntax [:] means from the start position to the end position of the copy.

The documentation mentions that if instead of the above syntax we used the syntax

for w in words:
  if(len(w) > 6):
     words.insert(0,w)

It would create an infinite list with the word 'defenestrate' being inserted over and over again.

Can someone please explain such behavior and also if I could find the answer to my question by referring some other documentation.

3
  • 5
    Because if you're iterating over a list while constantly adding items to the end of it, how do you ever reach the end? Commented Jul 28, 2019 at 9:55
  • This is adding an element to starting position words.insert(0,w) Commented Jul 28, 2019 at 13:03
  • That's true, sorry. You're still extending the length of the list, though. Commented Jul 28, 2019 at 13:11

3 Answers 3

2

I think what you are looking for is mentioned at https://docs.python.org/3/reference/compound_stmts.html#for

Note There is a subtlety when the sequence is being modified by the loop (this can only occur for mutable sequences, e.g. lists). An internal counter is used to keep track of which item is used next, and this is incremented on each iteration. When this counter has reached the length of the sequence the loop terminates. This means that if the suite deletes the current (or a previous) item from the sequence, the next item will be skipped (since it gets the index of the current item which has already been treated). Likewise, if the suite inserts an item in the sequence before the current item, the current item will be treated again the next time through the loop. This can lead to nasty bugs that can be avoided by making a temporary copy using a slice of the whole sequence, e.g.,

for x in a[:]:
    if x < 0: a.remove(x)
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the answer... this makes sense as once an element is added before the current position the max length internal variable increases by one and each time the current element is treated again and again and the loop never finishes .. right?
0
for w in words: # means every element in list
    if(len(w) > 6): # this means will run only 'defenestrate' as only its len is greater than 6
        words.insert(0, w) # this will add 'defenestrate' back again before ending

Comments

0

Using the second way, the loop will go over each word or element in words, since only 'defenestrate''s length is greater than 6, the loop will add a duplication of defenestrate to the beginning of the list. This means the loop will run again over defenestrate as that word is now in the next position of the list. Since the loop now grows by one word per loop, the loop with never reach the end of the list.

In the first way, this bug is fixed as the list iterated over is a copy, so when defenestrate is duplicated in the list, the list the loop is looking at remains unmodified and the loop ends

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.