Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mutate tuple of lists getting "'tuple' object does not support item assignment“ [duplicate]

I'm trying to modify a list in a tuple, the append method works, while += operator works yet with an exception raised saying tuple could not be modified. I know a tuple is immutable, but I'm not trying to mutate it. Why this happen?

In [36]: t=([1,2],)

In [37]: t[0].append(123)

In [38]: t
Out[38]: ([1, 2, 123],)

In [39]: t[0]+=[4,5,]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-39-b5b3001fbe03> in <module>()
----> 1 t[0]+=[4,5,]

TypeError: 'tuple' object does not support item assignment

In [40]: t
Out[40]: ([1, 2, 123, 4, 5],)
like image 616
zhangxaochen Avatar asked Oct 27 '25 04:10

zhangxaochen


1 Answers

+= is the in-place addition operator. It does two things:

  • it calls obj.__iadd__(rhs) to give the object the opportunity to mutate the object in-place.
  • it rebinds the reference to whatever the obj.__iadd__(rhs) call returns.

By using += on a list stored in a tuple, the first step succeeds; the t[0] list is altered in-place, but the second step, rebinding t[0] to the return value of t[0].__iadd__ fails because a tuple is immutable.

The latter step is needed to support the same operator on both mutable and immutable objects:

>>> reference = somestr = 'Hello'
>>> somestr += ' world!'
>>> somestr
'Hello world!'
>>> reference
'Hello'
>>> reference is somestr
False

Here a immutable string was added to, and somestr was rebound to a new object, because strings are immutable.

>>> reference = somelst = ['foo']
>>> somelst += ['bar']
>>> somelst
['foo', 'bar']
>>> reference
['foo', 'bar']
>>> reference is somestr
True

Here the list was altered in-place and somestr was rebound to the same object, because list.__iadd__() can alter the list object in-place.

From the augmented arithmetic special method hooks documentation:

These methods are called to implement the augmented arithmetic assignments (+=, -=, *=, /=, //=, %=, **=, <<=, >>=, &=, ^=, |=). 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).

The work-around here is to call t[0].extend() instead:

>>> t = ([1,2],)
>>> t[0].extend([3, 4, 5])
>>> t[0]
[1, 2, 3, 4, 5]
like image 187
Martijn Pieters Avatar answered Oct 29 '25 19:10

Martijn Pieters