Что произойдет при попытке изменить символ строки по индексу в Python и почему
Что проверяют
Понимаете ли вы изменяемость типов в Python, а не просто помните, что «будет ошибка». Следом спрашивают, почему тогда работает s += "x", какие ещё типы неизменяемы и как быстро собрать большую строку.
Как отвечать
Код s = "hello"; s[0] = "H" падает с TypeError: 'str' object does not support item assignment. Причина в том, что str неизменяемый тип: у него нет метода __setitem__, и никакая операция не меняет уже созданный объект.
Зачем так сделано:
- хэшируемость: строки служат ключами
dictи элементамиset. Если бы строку можно было поменять после вставки, её хэш перестал бы совпадать и словарь сломался бы; - безопасное разделение: одну строку держат десятки ссылок, и никто не изменит её под ногами у остальных;
- интернирование: CPython переиспользует один объект для одинаковых коротких строк и идентификаторов, что возможно только при неизменяемости.
Как получить изменённую строку, то есть новый объект:
- срезы:
s = "H" + s[1:]; replace: заменяет все вхождения, для одного нужен третий аргументcount;- список символов:
chars = list(s), правка, затем"".join(chars). Удобно, когда правок много; bytearray: изменяемый аналог для байтов.
s += "x" работает, потому что это присваивание: имя s привязывается к новой строке, а старый объект не меняется. Отсюда вывод про производительность: склейка в цикле может стоить квадратично, поэтому части собирают в список и объединяют через "".join() или пишут в io.StringIO.
Где спотыкаются
Называют не ту ошибку, например IndexError или AttributeError. IndexError будет только при обращении за границу строки.
Путают неизменяемость объекта с тем, что переменную нельзя переназначить. Имя s можно привязать к чему угодно, нельзя поменять сам объект.
Считают кортеж неизменяемым вглубь. t = ([1],) не даёт заменить элемент, но список внутри меняется, а t[0] += [2] одновременно выбросит TypeError и допишет элемент в список.