6

I couldn't find an explanation for the code in python doc article 4.2 regarding the for loop.

It mentioned something like: if we don't make a copy of the list, then it will print infinite list values for the list words = ['cat', 'window', 'defenestrate']; but not if we make a copy of it beforehand using "for w in words[:]". I need an explanation for this.

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

This code will run in an infinite loop, but not if we swap the for w inwordswithfor w in words[:]`

Sophie Gage
  • 5,391
  • 5
  • 24
  • 25
  • 8
    `words[:]` creates a copy of the list `words` so you are iterating over a copy but inserting to the original list. – Dan Oct 23 '19 at 10:32

2 Answers2

1

With [:] you create a copy of the list content at that moment, and that would be:

words = ['cat', 'window', 'defenestrate']  # equals words[:]

for i, w in enumerate(words[:]):
    print(i, w)
    if len(w) > 6:
        words.insert(0,w)
        print("len:", len(words))

#0 cat
#1 window
#2 defenestrate
#len: 4

But using the words variable itself, stepping your loop does nothing as your step forward is annulled with the insertion at the first position:

words = ['cat', 'window', 'defenestrate']

for i, w in enumerate(words):
    print(i, w)
    if len(w) > 6:
        words.insert(0,w)
        print("len:", len(words))

#0 cat
#1 window
#2 defenestrate
#len: 4
#3 defenestrate
#len: 5
#4 defenestrate
#len: 6
#5 defenestrate
#len: 7
#6 defenestrate
#len: 8
#7 defenestrate
#len: 9
#...
ipaleka
  • 3,745
  • 2
  • 13
  • 33
0

Using the [:] function in python creates a copy of a list. Let's take the following code as an example:

First, create a list: words

words = ['cat', 'window', 'defenestrate']

Create two new variables base on words:

words_copy = words[:] # this is a copy
words_ref = words # this is reference

The values are still equal:

assert words == words_copy
assert words == words_ref

but the menory lolcation isn't:

assert id(words) != id(words_copy)
assert id(words) == id(words_ref)

Next we'll modify the list (like you do in the loop):

words.append('foo')

Now the values aren't equal for the copy, but remain equal for the reference:

assert words != words_copy
assert words == words_ref
assert id(words) != id(words_copy)
assert id(words) == id(words_ref)

So by taking a copy of the array and using that in the loop, you're not modifying the object inside of the loop.

Simples!

Nick Martin
  • 731
  • 3
  • 17