20

I have face this weird behavior I can not find explications about.

MWE:

l = [1]
l += {'a': 2}
l
[1, 'a']
l + {'B': 3}
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: can only concatenate list (not "dict") to list

Basically, when I += python does not raise an error and append the key to the list while when I only compute the + I get the expected TypeError.

Note: this is Python 3.6.10

7
  • 1
  • 2
    See bugs.python.org/issue9314 - "inconsistent result when concatenating list with iterators". Also note += and so on are called "Augmented assignments" from the PEP introducing them, PEP 203.
    – alkasm
    Apr 27, 2020 at 10:52
  • That is something strange Apr 27, 2020 at 10:54
  • 6
    I think the bug link by @alkasm has a statment that explains it well. When a is mutable, a += b updates it in-place, so there is no ambiguity: the type of a cannot change. When you do a + b, there is no reason to treat a as more deserving than b when selecting the type of the result. Apr 27, 2020 at 10:58
  • @ChrisDoyle that is the exact reasoning. It is not "a bug", it's a mechanism that keeps the interpreter from guessing.
    – DeepSpace
    Apr 27, 2020 at 11:00

2 Answers 2

17

l += ... is actually calling object.__iadd__(self, other) and modifies the object in-place when l is mutable

The reason (as @DeepSpace explains in his comment) is that when you do l += {'a': 2} the operation updates l in place only and only if l is mutable. On the other hand, the operation l + {'a': 2} is not done in place resulting into list + dictionary -> TypeError.


(see here)


l = [1]
l = l.__iadd__({'a': 2})
l
#[1, 'a']

is not the same as + that calls object.__add__(self, other)

l + {'B': 3}
TypeError: can only concatenate list (not "dict") to list
6
  • 7
    This should also explain the reasoning. l += ... updates l in place, so the type of the result is clear (= the type of l). l + ... is ambiguous because it is not in place, so the type of the resulting new object is not clear (should it be the type of l or should it be the type of ...?)
    – DeepSpace
    Apr 27, 2020 at 10:58
  • 1
    of course! I added this to my answer. The l += ... operates in-place
    – seralouk
    Apr 27, 2020 at 11:20
  • @seralouk, do you mind sharing which tool you used to found out which function was invoked ? Inspect, pdb etc ?
    – surya
    May 7, 2020 at 5:20
  • the documentation: docs.python.org/3/reference/datamodel.html#object.__iadd__ and some programming knowledge e.g. dictionary are mutables.
    – seralouk
    May 7, 2020 at 7:45
  • @DeepSpace the reasoning makes sense, but __iadd__ is not guaranteed to return the same object. See number += 2. Also, from docs: These methods should attempt to do the operation in-place (modifying self) and return the result (which could be, but does not have to be, self) May 7, 2020 at 16:03
1

So as the authors say this is not a bug. When you Do a += b it is like b come to a's house and changing it the way that a like it to be. what the Authors say is when you do a + b it cannot be decided which one's style will get prioritized. and no one knows where will the result of a + b will go until you execute it. So you can't decide whose style it would be. if it is a style it would be [1, 'a']'s, and if it is b style it would be an error. and therefore it cannot be decided who will get the priority. So I don't personally agree with that statement. because when you take the call stack a is in a higher place than b. when there is a expression like a + b you first call a.__add__(self, other) if a.__add__ is NotImplemented (in this case it is implemented). then you call a.__radd__(self, other). which means call other.__add__ in this case b.__add__. I am telling this based on the place of the call stack and the python community may have more important reasons to do this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.