Here is the setup:
words = ['cat', 'window', 'defenestrate']
for w in words:
print(w, len(w))
Then I enter this:
>>> for w in words[:]: # Loop over a slice copy of the entire list.
... if len(w) > 6:
... words.insert(0, w)
...
I don't understand what the 0 in insert(0, w) is
doing. When I change it with another number
the output stays the same.
Final Input/Output:
>>> words
['defenestrate', 'cat', 'window', 'defenestrate']
-
2Why do you say the output stays the same? It doesn'tJohn Coleman– John Coleman2016年04月14日 18:03:10 +00:00Commented Apr 14, 2016 at 18:03
-
1It's interesting to note that none of the answers address the slice. Either your question wasn't clear about asking for that information or the title is misleading.jpmc26– jpmc262016年04月14日 19:46:12 +00:00Commented Apr 14, 2016 at 19:46
4 Answers 4
The first argument to insert tells insert at what index to place the new item in the list. Since you only have one word over 6 characters long, the code you've posted adds defenestrate to the beginning of the existing list.
From the docs:
list.insert(i, x)
Insert an item at a given position. The first argument is the index of the element before which to insert, so a.insert(0, x) inserts at the front of the list, and a.insert(len(a), x) is equivalent to a.append(x).
Comments
The 0 in (0, w) is the index where the word (w) will be inserted.
So your code is basically iterating through the list and placing any words greater than 6 characters in length at the beginning of the list.
For me, changing the index works as you would expect.
Index of 0
In [1]: words = ['cat', 'window', 'defenestrate']
In [2]: for w in words[:]:
...: if len(w) > 6:
...: words.insert(0, w)
...:
In [3]: words
Out[3]: ['defenestrate', 'cat', 'window', 'defenestrate']
Index of 1
In [1]: words = ['cat', 'window', 'defenestrate']
In [2]: for w in words[:]:
if len(w) > 6:
words.insert(1, w)
...:
In [3]: words
Out[3]: ['cat', 'defenestrate', 'window', 'defenestrate']
Index of 3
In [1]: words = ['cat', 'window', 'defenestrate']
In [2]: for w in words[:]:
if len(w) > 6:
words.insert(3, w)
...:
In [3]: words
Out[3]: ['cat', 'window', 'defenestrate', 'defenestrate']
Comments
I don't understand what the 0 in insert(0, w) is doing. When I change it with another number the output stays the same.
>>> for w in words[:]: # Loop over a slice copy of the entire list.
... if len(w) > 6:
... words.insert(0, w)
...
I've encountered this issue with python tutorial before, and here is my explanation.
Let's step back and look at the context:
This example is from Chapter 4 of the python Tutorial, but the line of code you are questioning references Chapter 5.1 of the same Tutorial.
The 'insert' method on lists is here: https://docs.python.org/2.7/tutorial/datastructures.html
The confusion is understandable if you are doing the Tutorial 'in order', which, of course, you should be, then you are unfamiliar with that line of code. Jump ahead to chapter 5.1, and see this:
list.insert(i, x) Insert an item at a given position. The first argument is the index of the element before which to insert, so a.insert(0, x) inserts at the front of the list, and a.insert(len(a), x) is equivalent to a.append(x).
The point the author is trying to show is that you want to make a copy of the list before modifying the list inside a loop, or 'bad things'TM can happen.
See: Thou Shalt Not Modify A List During Iteration
If you don't copy the list, the loop never finishes... try this:
>>> for w in words: # Loop over the list, and modify it while looping
... if len(w) > 6:
... words.insert(0, w)
...
You will be waiting until you run out of memory, but you are getting this:
['defenestrate', 'defenestrate', 'defenestrate', 'defenestrate', 'defenestrate', 'defenestrate', 'defenestrate', 'defenestrate', 'defenestrate', 'defenestrate', 'cat', 'window', 'defenestrate']
The reason is this:
- for loop gets 'w' from
words[0]: 'cat'len('cat') > 6isfalse- continue
- for loop gets 'w' from
words[1]: 'window'len('window') > 6isfalse- continue
- for loop gets 'w' from
words[2]: 'defenestrate'len('defenstrate') > 6istrue- insert...
wordsis now['defenestrate', 'cat', 'window', 'defenestrate']
- for loop gets 'w' from
words[3]: 'defenstrate'len('defenstrate') > 6istrue- insert...
wordsis now['defenstrate, 'defenestrate', 'cat', 'window', 'defenestrate']
- for loop gets 'w' from
words[4]: 'defenstrate'
... continues for infinity.
when you copy the list, this happens:
- for loop gets 'w' from THE COPY OF
words[3]- raise Exception: IndexError (because THE COPY OF
wordsis only 3 items long) - for loop handles exception by terminating loop.
- raise Exception: IndexError (because THE COPY OF
You never altered the copy of the 'words' list.
You are altering the original 'words' list.
The copy is anonymous. It's a variable only used to control the loop, and only available internal to the loop. It goes away when the loop terminates.
Comments
Changing the insert position should change the output, as shown below. The insert position (the '0' as you say) tells before which index in the list to insert into.
>>> words = ['cat', 'window', 'defenestrate']
>>> for w in words[:]:
... if len(w) > 6:
... words.insert(0,w)
...
>>> words
['defenestrate', 'cat', 'window', 'defenestrate']
>>> words = ['cat', 'window', 'defenestrate']
>>> for w in words[:]:
... if len(w) > 6:
... words.insert(2,w)
...
>>> words
['cat', 'window', 'defenestrate', 'defenestrate']