Подтвердить что ты не робот

Puzzling "'tuple' объект не поддерживает назначение элемента" error

Рассмотрим следующее:

>>> t = ([],)
>>> t[0].extend([12, 34])
>>> t
([12, 34],)
>>> t[0] += [56, 78]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t
([12, 34, 56, 78],)
>>> 

Я понимаю, что кортежи неизменяемы, но элемент в LHS не является кортежем! (Тот факт, что предполагаемое назначение фактически преуспело, несмотря на сообщение об ошибке, делает весь сценарий более причудливым.)

Почему это поведение не считается ошибкой?

4b9b3361

Ответ 1

t[0] += [56, 78]

не подходит для

t[0] = t[0].__iadd__([56, 78])

где t является кортежем. Часть t[0].__iadd__([56, 78]) изменяет список, но тогда результат не может быть сохранен как t[0].

LHS в Python всегда является именем, а не значением. В каждом выражении Python RHS оценивается до значения и присваивается имени на LHS. В этом случае имя t[0] не может быть назначено, потому что t является кортежем.

Ответ 2

Это описано и объяснено в FAQ Python.

Для полного обсуждения прочитайте раздел FAQ. Но вкратце, проблема в том, что этот код:

t[0] += [56, 78]

... эквивалентно этому:

t[0] = t[0].__iadd__([56, 78])

__iadd__ успешно изменяет list на месте и возвращает себя; то присваивание вызывает исключение.

Это не считается ошибкой, потому что это неизбежное последствие работы +=, list.__iadd__ и tuple. Хотя это не очевидно для всех, кто не понимает эти три вещи, любая попытка изменить ситуацию была бы намного неочевидна для всех, кто действительно понимал (и, вероятно, нарушит много других, более важных случаев).