Question

We know that Python tuples are immutable, good. When I attempt to change the reference of a tuple component I get an exception, as expected. What is not expected, is the component gets changed regardless of the exception, whereas I would have thought tuple immutability guarantees that the object won't be mutable.

Is it a bug, feature or a PEP?

In [6]: x=([1],)
In [7]: type(x)
Out[7]: tuple
In [8]: x[0]+=[2,3]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-8-a73186f99454> in <module>()
----> 1 x[0]+=[2,3]

TypeError: 'tuple' object does not support item assignment   
In [9]: x
Out[9]: ([1, 2, 3],)
Was it helpful?

Solution 2

Interesting point.

The reason it behaves like this is that

x[0]+=[2,3]

translates to

x[0] = x[0].__iadd__([2,3])

which means it first calls __iadd__, which modifies the list in place, and only then attempts to perform the illegal assignment into the tuple.

(Of course, it's easy to workaround (e.g. @luispedro's answer), but I understand your question is not about how to workaround it.)

Is it a bug, feature or a PEP?

Hard to say. I tend to vote for "a bug", because of the Principle of Least Astonishment. One would expect x[0].extend(y) to behave like a=x[0]; a.extend(y) to behave like a=x[0]; a+=y to behave like x[0]+=y.

A possible fix (at least for python built-in types) can be to required that __setitem__(self, k, v) should translate to no-op in case self[k] is v. (and custom classes overriding __setitem__ should obey).

OTHER TIPS

Here is even simpler:

tup = ([],[])
tup[0].append(0)
tup[1].append(1)
print tup

prints out

([0],[1])

Tuple immutability means that the objects that compose the tuple cannot be changed to different objects. It does not mean that you cannot modify their values.

Now, having said that, you found a very interesting (if that's the word) corner case, which basically translates to:

x = tup[0]
x += [2,3]
tup[0] = x

So, the first two lines work as expected, then you get an exception.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top