Python Iterators – Why Python Only Copies Individual Elements When Iterating a List

iteratorlistpython

I just realized that in Python, if one writes

for i in a:
    i += 1

The elements of the original list a will actually not be affect at all, since the variable i turns out to just be a copy of the original element in a.

In order to modify the original element,

for index, i in enumerate(a):
    a[index] += 1

would be needed.

I was really surprised by this behavior. This seems to be very counterintuitive, seemingly different from other languages and has resulted in errors in my code that I had to debug for a long while today.

I've read Python Tutorial before. Just to be sure, I checked the book again just now, and it doesn't even mention this behavior at all.

What is the reasoning behind this design? Is it expected to be a standard practice in a lot of languages so that the tutorial believes that the readers should get it naturally? In what other languages is the same behavior on iteration present, that I should pay attention to in the future?

Best Answer

I already answered a similar question lately and it's very important to realize that += can have different meanings:

  • If the data type implements in-place addition (i.e. has a correctly working __iadd__ function) then the data that i refers to is updated (doesn't matter if it's in a list or somewhere else).

  • If the data type doesn't implement an __iadd__ method the i += x statement is just syntactic sugar for i = i + x, so a new value is created and assigned to the variable name i.

  • If the data type implements __iadd__ but it does something weird. It could be possible that it's updated ... or not - that depends on what is implemented there.

Pythons integers, floats, strings don't implement __iadd__ so these will not be updated in-place. However other data types like numpy.array or lists implement it and will behave like you expected. So it's not a matter of copy or no-copy when iterating (normally it doesn't do copies for lists and tuples - but that as well depends on the implementation of the containers __iter__ and __getitem__ method!) - it's more a matter of the data type you have stored in your a.

Related Topic