Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Python iterate a for loop?

I tried the following code on Python, and this is what I got: It seems like for many changes I try to make to the iterables by changing elem, it doesn't work.

lis = [1,2,3,4,5]
for elem in lis:
    elem = 3

print lis
[1, 2, 3, 4, 5]

However if the iterables are objects with its own methods (like a list), they can be modified in a for loop.

lis = [[1],[2]]
for elem in lis:
    elem.append(8)

print lis
    [[1, 8], [2, 8]]

In the for loop what exactly is the 'elem' term? Thanks in advance!

like image 288
turtlesoup Avatar asked Aug 02 '12 20:08

turtlesoup


3 Answers

The reason that this doesn't work is because you're misunderstanding what elem is. It's not the object itself, and it's not even correct to call it a "variable".

It's a name, kind of like a label, that points to the object. If you just directly assign over it, you're just overwriting the name to point at something else. But, you still have the original reference to the list, so assigning a different value over elem doesn't modify lis itself.

Now, in this case, since all of the objects that elem points to are integers, you can't even change them at all - because integers (and many other types, like strings or tuples) are immutable. That means, simply put, that once the object has been created it cannot be modified. It has nothing to do with whether they "have methods" or not (all Python objects have methods, integers included), but on whether or not they are immutable.

Some objects, however, are mutable, meaning that they can be changed. Lists are examples of such objects. In your second example, elem is a name that references the list objects contained within lis, which themselves are mutable. That is why modifying them in-place (using .append(), or .remove(), etc) works fine.

like image 160
voithos Avatar answered Nov 07 '22 12:11

voithos


The elem variable in your for loop is a reference to the current object on each iteration. Changing it won't do anything; it will just change the value of the variable elem and that's going to be changed the next time through the loop anyway. To actually change the value of the element in the list, you need a reference to the list and the index of the element to be changed, and you don't have the latter.

So what you want to do is something like this:

for index, elem in enumerate(lis):
    lis[index] = 3

This way you have elem for the element's value and index for the position in the list. It saves you from writing lis[index] constantly to get values, but you must still do so to change elements.

You can also do:

for index in xrange(len(lis)):
    lis[index] = 3

However, in most situations this is considered un-Pythonic (among other things, what happens if the list gets longer or shorter while it's being iterated)?

like image 34
kindall Avatar answered Nov 07 '22 10:11

kindall


Here, you are actually modifying the list object in your second example. In the first example, you are not modifying the number, you are replacing it. This can be a complicated nuance for new users of Python.

Check this out:

>>> x = 1
>>> id(x)
4351668456
>>> x = 2
>>> id(x)
4351668432

id returns the identifier of the object. As you can see above, the object of x changes both of these times.

>>> y = [1]
>>> id(y)
4353094216
>>> y.append(2)
>>> id(y)
4353094216

Here, I modify the list, so the list is still the original object y.

So, all this means that when you are doing elem = 3, it's not modifying it, it is replacing it. And by now, it's not associated with the list anymore.

This is one of the ways you could do what you are trying to do. This grabs the index and then modifies the list, not the number.

lis = [1,2,3,4,5]
for idx, elem in enumerate(lis):
    lis[idx] = 3

print lis
[1, 2, 3, 4, 5]
like image 28
Donald Miner Avatar answered Nov 07 '22 11:11

Donald Miner