Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add to list vs. Increment

Tags:

python

Given that in Python:

element = element + [0]

should be equal to:

element += [0]

Why does one modify a list and the other does not? Here is a example:

>>> a = [[0, 0], [0,0]]
>>> for element in a:
...     element = element + [0]
... 
>>> a
[[0, 0], [0, 0]]

a is not modified. But if I increment:

>>> a = [[0, 0], [0,0]]
>>> for element in a:
...     element += [0]
...
>>> a
[[0, 0, 0], [0, 0, 0]]

a is modified.

Thanks, Frank

like image 301
iwander Avatar asked Dec 03 '11 22:12

iwander


People also ask

Does += work for a list?

For a list, += is more like the extend method than like the append method. With a list to the left of the += operator, another list is needed to the right of the operator. All the items in the list to the right of the operator get added to the end of the list that is referenced to the left of the operator.

Is set add faster than list append?

The set is far faster, in general. Testing for membership in a list is O(n), linear in the size of the list. Adding to a set is O(1), independent of the number of the items in the list.

Can you append a number to a list in Python?

Python provides a method called . append() that you can use to add items to the end of a given list.


3 Answers

This is a fun side-effect of += operatior, which calls __iadd__ instead of __add__.

The statement x = x + y is equivalent to x = x.__add__(y), while x += y is equivalent to x = x.__iadd__(y).

This lets the list class optimize += by extending the existing (ex, x += y is roughly equivalent to x.extend(y)) list instead of creating an entirely new list (which is what + needs to do).

For example:

>>> a = [1, 2, 3]
>>> original_a = a
>>> b = [1, 2, 3]
>>> original_b = b
>>> a += [4]
>>> b = b + [4]
>>> a is original_a
True
>>> b is original_b
False

You can see that using += maintains the identity of the left hand side (ie, a new list isn't created) while using + does not maintain the identity (ie, a new list is created).

For more, see: http://docs.python.org/library/operator.html#operator.iadd and the paragraph directly above the documentation for operator.iadd.

like image 104
David Wolever Avatar answered Nov 11 '22 08:11

David Wolever


In the first case, element = element + [0], you are creating a new list.

In the second case, element += [0], you are modifying an existing list.

Since the list of lists, a, contains pointers to the elements, only modifying the elements will actually change things. (That is, creating a new list does not change the pointers in a.)

This is seen more clearly if we take a simple example showing how lists work:

>>> a = [1, 2, 3]
>>> b = a
>>> a = [4, 5, 6]
>>> a
[4, 5, 6]
>>> b
[1, 2, 3]
>>> a = [1, 2, 3]
>>> b = a
>>> a += [4, 5, 6]
>>> b
[1, 2, 3, 4, 5, 6]
>>> a
[1, 2, 3, 4, 5, 6]

Assigning a variable to a list simply assigns a pointer.

like image 45
Ceasar Bautista Avatar answered Nov 11 '22 07:11

Ceasar Bautista


Adding to what others said, there is a difference in what these statements do:

element = element + [0]

does

element = element.__add__([0])

while

element += [0]

does

element = element.__iadd__([0])

__iadd__(), in this case, is free to determine what to return: the original object with a modification or a new object.

In the case of a immutable object, it must return a different one (e.g., a = b = 8; a += 9 => a is not b.

But in the case of a mutable object, such as a list, it normally modifies this one:

a = b = []
a += [8]

=> a is b.

This different behaviour reflects in your for loop:

for element in a:
   element = element + [0]

=> name element gets rebound to a different object; original one remains untouched

for element in a:
   element += [0]

=> original object, which is as well contained in the outer list, a, gets modified. The fact that element is reassigned is irrelevant; it is not used.

like image 45
glglgl Avatar answered Nov 11 '22 07:11

glglgl