-2

Just noticed something when I was mutating a list in python:

my_list = ['a','b','c','d','e']

Example 1

for letter in my_list:
    if letter == 'c':
        letter = 'x'

Example 2

for i in range(len(my_list)):
    if my_list[i] == 'c':
        my_list[i] = 'x'

Result 1

my_list = ['a','b','c','d','e']

Result 2

my_list = ['a','b','x','d','e']

So my question is it 'letter' not a direct reference to an element in 'my_list' ? Whats the difference between the two loops?

Tomy
  • 67
  • 1
  • 9

2 Answers2

0

Assuming its my_list[i] instead of letter in example 2

In example 1, when you do for letter in my_list, python iterates through the list and stores the value in the variable letter. Therefore, its like saying letter = my_list[i]. Now you can compare the letter, but changing the letter will not update the value in the my_list since letter is only a copy of the element of the list.

hyades
  • 3,110
  • 1
  • 17
  • 36
0

In example 1 letter is a simple variable, taking the value of each list element in turn. Changing it does not affect the list at all. I guess in example 2 "letter" should be replaced by "list[i]". In this case the list is modified.

The way I would write it is:

my_list = ["x" if letter == "c" else letter for letter in my_list]
guidot
  • 5,095
  • 2
  • 25
  • 37
  • @hyades: I don't care during processing if lists are reasonably small. Afterwards there is no difference (just the new list content survives), so what are you referring to? – guidot Sep 25 '14 at 09:29
  • 1
    @hyades It is true that we are throwing away to first list. But this is the pythonic way of solving this. If I would see a code like the second example in a production project, I would ask them to change it to list comprehension as \@guidot suggested here. To solve the memory problem, I would probably try to get rid of the first list if possible (by changing it to an iterator.) so first list would not exist in the first place. Also python lists are not arrays so in-place update will not work as good as you expect them to be anyway. – yilmazhuseyin Sep 25 '14 at 09:42
  • Also if you insist on doing in-place update you can use "for index,char in enumerate(my_list):". So you would get index values with the characters. – yilmazhuseyin Sep 25 '14 at 09:45
  • `map(lambda x: 'x' if x=='c' else x, l)`. @yilmazhuseyin any insight into this way also? Just trying comparing all these ways finding which should be best. – hyades Sep 25 '14 at 10:31
  • @hyades: asked before, see [here](http://stackoverflow.com/questions/1247486/python-list-comprehension-vs-map). Summary: lower readbility, minimum performance benefit. – guidot Sep 25 '14 at 12:16
  • 1
    @hyades like \@guidot mentioned, for this particular example, list comprehensions are more readable. And python community is going towards the list comprehensions rather than higher order functions (Because Guido doesn't like higher order functions :) ). I personally prefer using higher order functions for some cases. Here is an example: parsing list of integer strings to integer map(int, str_list) I think it is a lot better than [int(i) for i in str_list]. – yilmazhuseyin Sep 26 '14 at 08:15