← Назад к вопросам
Что будет если к списку находящемуся в кортеже через оператор += присвоить список?
1.0 Junior🔥 171 комментариев
#Другое
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Список в кортеже и оператор +=
Это классический вопрос, который показывает, что разработчик путает mutability и immutability в Python. Ответ — интересный и парадоксальный.
Что произойдёт
# Создаём кортеж со списком
tup = ([1, 2, 3], "hello")
print(tup) # ([1, 2, 3], 'hello')
# Используем +=
tup[0] += [4, 5]
# Результат: TypeError!
# TypeError: 'tuple' object does not support item assignment
Но вот что интересно...
# Хотя произойдёт ошибка...
tup = ([1, 2, 3], "hello")
try:
tup[0] += [4, 5] # Ошибка!
except TypeError as e:
print(f"Error: {e}")
# ...но список ИЗМЕНИЛСЯ!
print(tup) # ([1, 2, 3, 4, 5], 'hello')
print(tup[0]) # [1, 2, 3, 4, 5] <- Изменён!
Почему это происходит?
Ключ — в том, как Python обрабатывает +=:
# a += b эквивалентно:
# 1. temp = a.__iadd__(b) <- in-place operation
# 2. a = temp <- assignment
# Для списков __iadd__ ИЗМЕНЯЕТ список in-place:
tup[0] += [4, 5]
# Это примерно то же самое, что:
temp = tup[0].__iadd__([4, 5]) # Список изменяется!
assignment = tup[0] = temp # А вот тут происходит ошибка!
Детальный разбор
Шаг 1: In-place операция происходит:
tup = ([1, 2, 3], "hello")
# Список в памяти изменяется
tup[0].__iadd__([4, 5]) # Работает! Список изменился
print(tup[0]) # [1, 2, 3, 4, 5]
Шаг 2: Assignment падает:
# Потом Python пытается переassign элемент кортежа
tup[0] = temp # TypeError: 'tuple' object does not support item assignment
# Кортежи immutable!
Практический пример
class DemonstrationOfTheIssue:
def __init__(self):
self.lst = [1, 2, 3]
self.tup = (self.lst, "hello")
def show_the_problem(self):
print(f"Before: {self.tup}")
print(f"List id: {id(self.tup[0])}")
try:
self.tup[0] += [4, 5]
except TypeError as e:
print(f"\nGot error: {e}")
# НО СПИСОК ИЗМЕНИЛСЯ!
print(f"\nAfter: {self.tup}")
print(f"List id: {id(self.tup[0])}")
# id одинаковый — это ТОТ ЖЕ список!
demo = DemonstrationOfTheIssue()
demo.show_the_problem()
# Output:
# Before: ([1, 2, 3], 'hello')
# List id: 140234567890000
#
# Got error: 'tuple' object does not support item assignment
#
# After: ([1, 2, 3, 4, 5], 'hello')
# List id: 140234567890000 <- Тот же объект!
Почему это важно понимать
# Это создаёт неожиданное поведение
data = ([1, 2, 3], "info")
# Кажется, что это не сработает...
try:
data[0] += [4, 5]
except TypeError:
pass # Ошибка!
# ...но данные изменились!
assert data[0] == [1, 2, 3, 4, 5] # True!
# Это может привести к трудноуловимым багам:
original = ([1, 2], "name")
backup = original # Кортежи типа "pass by reference"
try:
original[0] += [3, 4]
except TypeError:
pass
print(backup[0]) # [1, 2, 3, 4] <- Изменился и backup!
# Потому что backup указывает на ТОТ ЖЕ кортеж и ТОТ ЖЕ список
Как это происходит на уровне bytecode
import dis
def modify_tuple():
tup = ([1, 2, 3], "hello")
tup[0] += [4, 5]
dis.dis(modify_tuple)
# Результат (упрощённо):
# LOAD_NAME тup
# LOAD_CONST 0 (индекс 0)
# DUP_TOP_TWO
# BINARY_SUBSCR <- Получаем список
# LOAD_NAME [4, 5]
# INPLACE_ADD <- Изменяем список in-place!
# ROT_TWO
# STORE_SUBSCR <- Пытаемся переassign... ОШИБКА!
Правильные способы работы
1. Изменять список напрямую (правильно):
tup = ([1, 2, 3], "hello")
tup[0].extend([4, 5]) # Работает!
print(tup) # ([1, 2, 3, 4, 5], 'hello')
2. Использовать список, а не кортеж:
lst = [[1, 2, 3], "hello"]
lst[0] += [4, 5] # Работает!
print(lst) # ([1, 2, 3, 4, 5], 'hello')
3. Если нужна immutability, использовать immutable структуры:
from typing import Tuple
# Правильно: кортеж с immutable данными
tup: Tuple[tuple, str] = ((1, 2, 3), "hello")
# tup[0] += (4, 5) # Это создаст новый кортеж, не ошибку
new_tup = (tup[0] + (4, 5), tup[1])
print(new_tup) # ((1, 2, 3, 4, 5), 'hello')
Вывод
Главное правило:
- Кортежи immutable — нельзя менять элементы
- Но объекты внутри кортежа могут быть mutable — их можно менять
+=для списка =__iadd__(изменение in-place) + assignment- Изменение происходит, assignment падает → парадокс
Это отличный пример, почему важно знать разницу между mutable и immutable, и как Python обрабатывает операции на уровне bytecode.