Why does accessing list items via index in a function work when changing its value, but the iterator variable way doesn't?

Viewed 59

I am trying to increment the elements of a list by passing it into a increment() function that I have defined.

I have tried two ways to do this.

  • Accessing using the index.
# List passed to a function

def increment(LIST):
    for i in range(len(LIST)):
        LIST[i] += 1
    return LIST

li = [1, 2, 3, 4]
li = increment(li)
print(li)

This outputs the desired result: [2, 3, 4, 5]

  • Accessing using iterator variables.
# List passed to a function

def increment(LIST):
    for item in LIST:
        item += 1
    return LIST

li = [1, 2, 3, 4]
li = increment(li)
print(li)

This outputs: [1, 2, 3, 4]

I wish to know the reason behind this difference.

2 Answers

Python's in-place operators can be confusing. The "in-place" refers to the current binding of the object, not necessarily the object itself. Whether the object mutates itself or creates a new object for the in-place binding, depends on its own implementation.

If the object implements __iadd__, then the object performs the operation and returns a value. Python binds that value to the current variable. That's the "in-place" part. A mutable object may return itself whereas an immutable object returns a different object entirely. If the object doesn't implement __iadd__, python falls back to several other operators, but the result is the same. Whatever the object chooses to return is bound to the current variable.

In this bit of code

for item in LIST:
    item += 1

a value of the list is bound to a variable called "item" on each iteration. It is still also bound to the list. The inplace add rebinds item, but doesn't do anything to the list. If this was an object that mutated itself with iadd, its still bound to the list and you'll see the mutated value. But python integers are immmutable. item was rebound to the new integer, but the original int is still bound to the list.

Which way any given object works, you kinda just have to know. Immutables like integers and mutables like lists are pretty straight forward. Packages that rely heavily on fancy meta-coding like pandas are all over the map.

The reasoning behind this is because integers are immutable in python. You are essentially creating a new integer when performing the operation item +=1

This post has more information on the topic

If you wished to update the list, you would need to create a new list or update the list entry.

def increment(LIST):
    result = []
    for item in LIST:
        result.append(item+1)
    return result

li = [1, 2, 3, 4]
li = increment(li)
print(li)
Related