24

consider the following code:

>>> x = y = [1, 2, 3, 4]
>>> x += [4]
>>> x
[1, 2, 3, 4, 4]
>>> y
[1, 2, 3, 4, 4]

and then consider this:

>>> x = y = [1, 2, 3, 4]
>>> x = x + [4]
>>> x
[1, 2, 3, 4, 4]
>>> y
[1, 2, 3, 4]

Why is there a difference these two?

(And yes, I tried searching for this).

S Singh
  • 443
  • 1
  • 3
  • 7
  • 4
    What is interesting about your last statement, is that this functionality is actually explained in the python docs: http://docs.python.org/reference/datamodel.html#object.__add__ (from searching about those terms) – jdi Mar 19 '12 at 07:27
  • 4
    @jdl: Yes I admit that I overlooked that. – S Singh Mar 19 '12 at 07:29

3 Answers3

34

__iadd__ mutates the list, whereas __add__ returns a new list, as demonstrated.

An expression of x += y first tries to call __iadd__ and, failing that, calls __add__ followed an assignment (see Sven's comment for a minor correction). Since list has __iadd__ then it does this little bit of mutation magic.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • 4
    If you want more details on this exact behavior and other insights into why Python is the way it is - I would highly recommend the [python epiphanies talk](http://pyvideo.org/video/613/python-epiphanies) from PyCon 2012. It will lead you to a lot of 'a ha!' moments. – Burhan Khalid Mar 19 '12 at 08:19
  • @S Singh if you get your answer then please select the answer as accepted answer and complete the workflow. Otherwise this question will be shown as unanswered. – Nilesh Mar 19 '12 at 08:23
  • 3
    This answer is slightly misleading: The assignment is always performed, regardless whether `__iadd__()` or `__add__()` is called. `list.__iadd__()` simply returns `self`, though, so the assignment has no effect other than rendering the target name local to the current scope. – Sven Marnach Mar 19 '12 at 15:23
  • 1
    Also: `__iadd__` works faster for lists (it changes object in-place instead of recreating one); it allows to append any iterable, `a = []` `a+=range(5)` works for lists, and `a = a + smth` requires `smth` to be an instance of list – thodnev Aug 06 '16 at 06:17
  • @thodnev "it allows to append any iterable" -- Wow, this must be the first time I see this sort of type coercion between built-in types in 13 years of doing Python. It is beyond me how anyone would think it'd be a good idea to make `__add__` and `__iadd__` behave so surprisingly differently. – balu Dec 16 '22 at 11:49
5

The first mutates the list, and the second rebinds the name.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
1

1)'+=' calls in-place add i.e iadd method. This method takes two parameters, but makes the change in-place, modifying the contents of the first parameter (i.e x is modified). Since both x and y point to same Pyobject they both are same.

2)Whereas x = x + [4] calls the add mehtod(x.add([4])) and instead of changing or adding values in-place it creates a new list to which a points to now and y still pointing to the old_list.

Jolly
  • 126
  • 6