Merge #17973: Add FAQ entry for ([],)[0] += [1] both extending and raising.
This commit is contained in:
commit
63f72908a1
|
@ -1103,6 +1103,89 @@ Use a list comprehension::
|
||||||
result = [obj.method() for obj in mylist]
|
result = [obj.method() for obj in mylist]
|
||||||
|
|
||||||
|
|
||||||
|
Why does a_tuple[i] += ['item'] raise an exception when the addition works?
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
This is because of a combination of the fact that augmented assignment
|
||||||
|
operators are *assignment* operators, and the difference between mutable and
|
||||||
|
immutable objects in Python.
|
||||||
|
|
||||||
|
This discussion applies in general when augmented assignment operators are
|
||||||
|
applied to elements of a tuple that point to mutable objects, but we'll use
|
||||||
|
a ``list`` and ``+=`` as our exemplar.
|
||||||
|
|
||||||
|
If you wrote::
|
||||||
|
|
||||||
|
>>> a_tuple = (1, 2)
|
||||||
|
>>> a_tuple[0] += 1
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
TypeError: 'tuple' object does not support item assignment
|
||||||
|
|
||||||
|
The reason for the exception should be immediately clear: ``1`` is added to the
|
||||||
|
object ``a_tuple[0]`` points to (``1``), producing the result object, ``2``,
|
||||||
|
but when we attempt to assign the result of the computation, ``2``, to element
|
||||||
|
``0`` of the tuple, we get an error because we can't change what an element of
|
||||||
|
a tuple points to.
|
||||||
|
|
||||||
|
Under the covers, what this augmented assignment statement is doing is
|
||||||
|
approximately this::
|
||||||
|
|
||||||
|
>>> result = a_tuple[0].__iadd__(1)
|
||||||
|
>>> a_tuple[0] = result
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
TypeError: 'tuple' object does not support item assignment
|
||||||
|
|
||||||
|
It is the assignment part of the operation that produces the error, since a
|
||||||
|
tuple is immutable.
|
||||||
|
|
||||||
|
When you write something like::
|
||||||
|
|
||||||
|
>>> a_tuple = (['foo'], 'bar')
|
||||||
|
>>> a_tuple[0] += ['item']
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
TypeError: 'tuple' object does not support item assignment
|
||||||
|
|
||||||
|
The exception is a bit more surprising, and even more surprising is the fact
|
||||||
|
that even though there was an error, the append worked::
|
||||||
|
|
||||||
|
>>> a_tuple[0]
|
||||||
|
['foo', 'item']
|
||||||
|
|
||||||
|
To see why this happens, you need to know that for lists, ``__iadd__`` is equivalent
|
||||||
|
to calling ``extend`` on the list and returning the list. That's why we say
|
||||||
|
that for lists, ``+=`` is a "shorthand" for ``list.extend``::
|
||||||
|
|
||||||
|
>>> a_list = []
|
||||||
|
>>> a_list += [1]
|
||||||
|
>>> a_list
|
||||||
|
[1]
|
||||||
|
|
||||||
|
is equivalent to::
|
||||||
|
|
||||||
|
>>> result = a_list.__iadd__([1])
|
||||||
|
>>> a_list = result
|
||||||
|
|
||||||
|
The object pointed to by a_list has been mutated, and the pointer to the
|
||||||
|
mutated object is assigned back to ``a_list``. The end result of the
|
||||||
|
assignment is a no-op, since it is a pointer to the same object that ``a_list``
|
||||||
|
was previously pointing to, but the assignment still happens.
|
||||||
|
|
||||||
|
Thus, in our tuple example what is happening is equivalent to::
|
||||||
|
|
||||||
|
>>> result = a_tuple[0].__iadd__(['item'])
|
||||||
|
>>> a_tuple[0] = result
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
TypeError: 'tuple' object does not support item assignment
|
||||||
|
|
||||||
|
The ``__iadd__`` succeeds, and thus the list is extended, but even though
|
||||||
|
``result`` points to the same object that ``a_tuple[0]`` already points to,
|
||||||
|
that final assignment still results in an error, because tuples are immutable.
|
||||||
|
|
||||||
|
|
||||||
Dictionaries
|
Dictionaries
|
||||||
============
|
============
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue