0

I was thinking this question should be asked on SO, but I was not able to find it somehow(Let me know in the comment section if there was one, i will delete this post)

It has came to my attention that when we do list replacement, it only works if we are loop through the list by index. Why?

myList = ['a','b','c','d','e']
for item in myList:
    if item == 'a':
        item = 's'
print("First loop:",myList)           //It prints ['a','b','c','d','e']


for i in range(len(myList)):
    if myList[i] == 'a':
        myList[i] = 's'
print("Second loop:",myList)          //It prints ['s','b','c','d','e']

I have tried to read the python control flow documentation: https://docs.python.org/3/tutorial/controlflow.html but it does not really answer my question.

ZpfSysn
  • 807
  • 2
  • 12
  • 30
  • Assigning to a name is fundamentally different from assigning to an *indexed* name (where `myList[i] = 's'` is actually a method call `myList.__setitem__(i, 's')`). – chepner Nov 01 '17 at 15:42
  • 1
    In your second to last line, I think you meant to use "=", not "==". – Markus Nov 01 '17 at 15:45
  • @Markus good call, it was a silly typo. – ZpfSysn Nov 01 '17 at 15:46
  • @chepner so is the first loop doing this: item = myList[index], since it is stored in a local variable, it does not affect the original list? – ZpfSysn Nov 01 '17 at 15:50

4 Answers4

3

In the first loop, the line item = 's' only changes the value of the locale variable item inside the loop, which is updated in each iterations by the next value in the list. It is not a reference to the list itself.

  • So in general list manipulation, it is more preferable to access the item using index? – ZpfSysn Nov 01 '17 at 15:45
  • Yes. Otherwise, you have to build a new list, or to find the index of the current item with the function index(), which is not always as accurate as wanted (in case of multiple identical values), slow and, according to my opignon, ugly. – André Nasturas Nov 01 '17 at 15:50
  • You could also use the [enumerate](https://docs.python.org/3/library/functions.html#enumerate) function, which gives you a tuple with the index and the value at the same time. – André Nasturas Nov 01 '17 at 15:53
2

In your first for loop, "item" is just a variable that gets assigned to whichever list item the loop has got to. Reassigning the variable doesn't affect the list. In the second loop, you directly change the list item, which is why it shows up when you print the list.

SuperStew
  • 2,857
  • 2
  • 15
  • 27
1

In each iteration of the first loop, the variable item gets assigned to each item in the list. When the if condition is satisfied, you then only reassign the variable item to 's', but that does not change the content of the list.

In the second loop, you are re-assigning the contents of my_list, as you are assigning the ith item to 's' with the line.

    myList[i] = 's'

Consider also a simpler example:

    myList = ['a', 'b', 'c']
    item = myList[0]  # assign item to 'a'
    item = 's'  # re-assign item variable to 's', does not change list
    myList[0] = 's'  # change the content of the first item in the list

Also have a look at this: Python : When is a variable passed by reference and when by value?

chepner
  • 497,756
  • 71
  • 530
  • 681
Fabian Ying
  • 1,216
  • 1
  • 10
  • 15
1

For an example of why the first loop doesn't work, check this:

myList = ['a','b','c','d','e']
item = myList[0]
item = 's'

# this is an example equivalent to what the first loop does
# the values in myList remain unchanged

And an example equivalent to the second loop:

myList = ['a','b','c','d','e']
myList[0] = 's'

# the first value in myList is changed to 's'
araraonline
  • 1,502
  • 9
  • 14