I know I'm not supposed to modify the list inside a loop, but just out of curiosity, I would like to know why the number of iterations is different between the following two examples.
Example 1:
x = [1, 2, 3, 4, 5]
for i, s in enumerate(x):
del x[0]
print(i, s, x)
Example 2:
x = [1,2,3,4,5]
for i, s in enumerate(x):
x = [1]
print(i, s, x)
Example 1 runs only 3 times because when i==3
, len(x)==2
.
Example 2 runs 5 times even though len(x)==1
.
So my question is, does enumerate
generate a full list of (index, value)
pairs at the beginning of the loop and iterate through it? Or are they generated on each iteration of the loop?
Python enumerate() Function The enumerate() function takes a collection (e.g. a tuple) and returns it as an enumerate object. The enumerate() function adds a counter as the key of the enumerate object.
Instead of using the range() function, we can instead use the built-in enumerate() function in python. enumerate() allows us to iterate through a sequence but it keeps track of both the index and the element. The enumerate() function takes in an iterable as an argument, such as a list, string, tuple, or dictionary.
enumerate is faster when you want to repeatedly access the list/iterable items at their index. When you just want a list of indices, it is faster to to use len() and range (xrange in Python 2. x).
Using enumerate() is more beautiful but not faster for looping over a collection and indices. Mind your Python version when looping over two collections - use itertools for Python 2.
In the first example, you're actually modifying the list you're iterating over.
On the other hand, in the second case, you're only assigning a new object to the name x
. The object the loop iterates over does not change, though.
Have a look at http://foobarnbaz.com/2012/07/08/understanding-python-variables/ for a more detailed explanation about names and variables in Python.
enumerate() returns an iterator, or some other object which supports iteration. The __next__() method of the iterator returned by enumerate() returns a tuple containing a count (from start which defaults to 0) and the values obtained from iterating over iterable.
__next__() returns the next item from the container. If there are no further items, raise the StopIteration
exception.
Does enumerate() generate a full list of (index, value) pairs at the beginning of the loop and iterates through it? Or are they generated on each iteration of the loop?
So, enumerate()
returns an iterator and at every iteration, __next__()
checks if there are further items. enumerate()
doesn't create a full list at the beginning of the loop.
As, @Wisperwind mentioned, in your second case, you're assigning a new object to the name x
. The object, the loop iterates over does not change during the iteration.
Just a clarification to what Wasi Ahmad and Wisperwind have said. Both state that "you're only assigning a new object to the name x". This might be slightly confusing as it might be interpreted as saying "you're creating a new object ([1]
) and storing it to the name x
, to which you'd say "Well yah, so why isn't it changing?!" To see what's happening, print out the id of the object
x = [1, 2, 3, 4, 5]
y = x # To keep a reference to the original list
print id(x), id(y)
for i, v in enumerate(x):
x = [1]
print id(x), id(y)
print id(x), id(y)
# output (somewhat contrived as I don't have a python environment set up)
# X ID Y ID
10000000000001 10000000000001
10000000000002 10000000000001
10000000000003 10000000000001
10000000000004 10000000000001
10000000000005 10000000000001
10000000000006 10000000000001
10000000000006 10000000000001
You'll notice that the id
of x
is changing each time through the loop and when you're finished with the loop, x
will point to the last modification made in the loop. When you're going through your loop, it is iterating over the original instance of x, regardless of whether you can still reference it.
As you can see, y
points to the original x
. As you make your iterations through the loop, even though x
is changing, y
is still pointing to the original x
which is still being looped over.
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