Назначение изменяемого компонента кортежа в python: ошибка? особенность?

Мы знаем, что кортежи Python неизменны, хорошо. Когда я пытаюсь изменить ссылку компонента кортежа, я получаю исключение, как и ожидалось. Что не ожидается, так это то, что компонент изменяется независимо от исключения, тогда как я бы подумал, что неизменность кортежа гарантирует, что объект не будет изменяемым.

Это ошибка, функция или ПКП?

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],)

2 ответа

Решение

Интересный момент.

Причина, по которой он ведет себя так:

x[0]+=[2,3]

переводит на

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

что означает, что сначала звонит __iadd__, который изменяет список на месте и только затем пытается выполнить недопустимое назначение в кортеж.

(Конечно, это легко обойти (например, ответ @luispedro), но я понимаю, что ваш вопрос не о том, как обойти это.)

Это ошибка, функция или ПКП?

Тяжело сказать. Я склонен голосовать за "ошибку" из-за принципа наименьшего удивления. Можно было ожидать x[0].extend(y) вести себя как a=x[0]; a.extend(y) вести себя как a=x[0]; a+=y вести себя как x[0]+=y,

Возможное исправление (по крайней мере для встроенных типов Python) может потребовать, чтобы __setitem__(self, k, v) следует перевести на no-op в случае self[k] is v, (и переопределение пользовательских классов __setitem__ должен подчиняться).

Здесь еще проще:

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

распечатывает

([0],[1])

Неизменность кортежа означает, что объекты, составляющие кортеж, не могут быть изменены на другие объекты. Это не значит, что вы не можете изменять их значения.

Сказав это, вы нашли очень интересный (если это слово) угловой случай, который в основном означает:

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

Итак, первые две строки работают как положено, затем вы получите исключение.

Другие вопросы по тегам