list in a tuple

Arnaud Delobelle arnodel at googlemail.com
Mon Dec 24 11:08:09 EST 2007


On Dec 24, 3:22 pm, montyphy... at gmail.com wrote:
> Recently, I got into a debate on programming.reddit.com about
> what should happen in the following case:
>
> >>> a = ([1], 2)
> >>> a[0] += [3]
>
> Currently, Python raises an error *and* changes the first element of
> the tuple. Now, this seems like something one would want to
> change - why raise an error *and* execute the thing it
> was complaining about? The discussion seems to have no end, and
> that is why I'm posting here. I would like to know what is the opinion
> of the people on this group... Am I really mistaking for thinking that
> this is strange and unwanted behavior? Btw I understand *why* is this
> happening, I just think it should change...
> And here is the post that started this discussion:http://filoxus.blogspot.com/2007/12/python-3000-how-mutable-is-immuta...
>
> Thanks for your replies

For the sake of clarity, say you have typed:

>>> L = [1]
>>> a = (L, 2)
>>> a[0] += [3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> a
([1, 3], 2)


I think that this is what happens when a[0] += [3] is executed:

1. list.__iadd__(L, [3]) is called, modifying L in place and returning
L.
2. tuple.__setitem__(a, L) is tried, raising the TypeError.

Notice that this problem doesn't arise when replacing lists with
tuples:

>>> a = ( (1,), 2)
>>> a[0] += (3, )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> a
((1,), 2)

This is because tuple object don't have an __iadd__ method so a new
object tuple.__add__((1,),(3,)) is created and returned.

AFAICS, the only way to avoid the error message would be to check if
the new object is the same as the old one before raising the
TypeError:

class mytuple(tuple):
    "It's ok to do t[i] = obj as long as t[i] was already obj"
    def __setitem__(self, i, val):
        if self[i] is not val:
            raise TypeError("'mytuple' object is immutable")

So:

>>> a = mytuple(([1], 2))
>>> a[0] += [3] # This now works
>>> a[1] += 4   # This won't work as ints are immutable
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "tuple.py", line 4, in __setitem__
    raise TypeError("'mytuple' object is immutable")
TypeError: 'mytuple' object is immutable
>>> a
([1, 3], 2)

It wouldn't slow anything down I suppose, just make some currently
failing code succeed.

--
Arnaud




More information about the Python-list mailing list