12
>>> b = []
>>> c = '1234'
>>> b += c
>>> b
['1', '2', '3', '4']
>>> 

What is happening here? This should not work, right? Or am I missing something obvious?

>>> b = []
>>> c = '1234'
>>> b + c
Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    b + c
TypeError: can only concatenate list (not "str") to list
>>> 

Then a += b is not always equivalent to a = a + b ?

Georgy
  • 12,464
  • 7
  • 65
  • 73
joaquin
  • 82,968
  • 29
  • 138
  • 152
  • 1
    Is this behaviour still present in Python 3.x? I always found it irritating that a standard library type breaks the general contract that `a += b` <=> `a = a + b` (without affecting any other references to the original `a` value). – Karl Knechtel Nov 30 '11 at 09:01
  • 2
    @Karl Knechtel: unfortunately, it's still present in Python 3.2.1. – Cristian Ciupitu Nov 30 '11 at 09:16
  • I was checking it in python 3.2, yes. I found the issue looking at a beginner code that was producing wrong results. I could not find any reference to this specific behavior in `Learning Python`. I checked PEP203 and it says that `__iadd__` is used but also they say that `__iadd__` is the inplace `__add__` that is not the case in this case... Maybe someone could explain the rational beneath this behavior or point/link to some discussion about that? I understand from Karl's comment that there is people concerned about it – joaquin Nov 30 '11 at 10:28

7 Answers7

16

Strings are iterable: the elements are the string's characters. When you add an iterable to a list, the iterable's elements get appended to the list.

Either of the following will do what you're expecting (i.e. append the string, not extend the list with the string's characters):

b += [c]

or

b.append(c)
NPE
  • 486,780
  • 108
  • 951
  • 1,012
10

The += operator extends a list instead of appending to it:

>>> b = []
>>> c = "1234"
>>> b.append(c)
>>> b
['1234']
>>> b.extend(c)
>>> b
['1234', '1', '2', '3', '4']
>>> b += c
>>> b
['1234', '1', '2', '3', '4', '1', '2', '3', '4']
>>> b += [c]
>>> b
['1234', '1', '2', '3', '4', '1', '2', '3', '4', '1234']
Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
  • do you know a source of documentation on the effect of these operators (`+`, `+=`) for iterables/sequences/... ? – moooeeeep Nov 30 '11 at 08:33
  • 1
    @moooeeeep - in [the table in the docs](https://docs.python.org/3/library/stdtypes.html#mutable-sequence-types) - you can also see how it happens in the actual source. – wwii Feb 21 '21 at 16:35
3

This is an answer not to the original question (which I think has been adequately answered), but to the numerous questions that have been asked in the comments about the semantics of augmented assignment (+= and similar operations).

In a nutshell: Augmented assignment works differently for mutable types than for immutable ones.

str, tuple, and the numeric types, among others, are immutable. The contents of a tuple cannot be changed once it has been created, so you get this behavior:

>>> a = (1, 2)
>>> b = a
>>> a += (3, 4)
>>> a
(1, 2, 3, 4)
>>> b
(1, 2)

str has the same semantics. Basically, a += b is equivalent to a = a + b if a is immutable.

Most other types, including list, are mutable. A list's contents can be changed in place, and augmented assignment does exactly that. Hence:

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

Whereas if the third line were replaced with a = a + [3, 4], a new list would be created and b would be [1, 2].

For a user-defined class, the semantics depend on how it was implemented, but this is how it's supposed to be done per PEP 203.

Taymon
  • 24,950
  • 9
  • 62
  • 84
  • This is a really good observation. `a` and `b` share the same memory address until `a` is evaluated on the left hand side of an assignment operator? Could you include that? – yurisich Dec 28 '11 at 12:20
2

A string is a sequence of characters. The list operation += takes any sequence and appends each of the sequence's elements to the list.

(Actually += takes any iterable.)

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • 2
    `+` is a different operator than `+=`. – rob mayoff Nov 30 '11 at 08:07
  • I know, it is called augmented assigment and it is defined to be equivalent to a = a + b (see PEP203). Taking this definition strictly drive me to a wrong expectation. That is what surprised me (probably I never dared to add a list to a string in my python code so I never collided with this before). Should not be `In the face of ambiguity, refuse the temptation to guess` ?. – joaquin Nov 30 '11 at 10:22
  • Nowhere in PEP-203 does it claim that `a += b` is equivalent to `a = a + b`. – chepner Jan 12 '22 at 14:03
2

+= is syntactic sugar for extend, but + is just list concatenation. If you extend, you'll iterate over the argument, which in this case is a string. But you can't concatenate a string to a list, hence + fails.

Philip Uren
  • 356
  • 1
  • 5
  • 14
0

What did you expect? If you want to add c as string you must to do:

b.append(c)

Cheers!

osanchezmon
  • 544
  • 1
  • 4
  • 18
0

In essence, the += operator on the list will retrieve c's iterator, which will yield the individual characters in order. If you intended to add the actual string to the list, yielding the result ['1234'], you can use b.append('1234') instead.

David Burström
  • 1,592
  • 14
  • 14