Представьте себе язык под названием FakeMutablePython, в котором вы можете изменять строки, используя списки и т. Д. (Например, mystr[0] = 'a'
)
a = "abc"
Это создает запись в памяти по адресу памяти 0x1, содержащую «abc» и идентификатор a
, указывающий на нее.
Теперь, скажи, что ты делаешь ..
b = a
Это создает идентификатор b
, а также указывает на тот же адрес памяти 0x1
Теперь, если строка была изменчивой, и вы изменили b
:
b[0] = 'z'
Это изменяет первый байт строки, хранящейся в диапазоне от 0x1 до z
. Так как здесь указывается идентификатор a
, таким образом, эта строка также будет изменена, поэтому ..
print a
print b
.. будет выводить zbc
Это может привести к очень странному, неожиданному поведению. Ключи словаря были бы хорошим примером этого:
mykey = 'abc'
mydict = {
mykey: 123,
'zbc': 321
}
anotherstring = mykey
anotherstring[0] = 'z'
Теперь в FakeMutablePython все становится довольно странным - у вас изначально есть два ключа в словаре, «abc» и «zbc». Затем вы изменяете строку «abc» (через идентификатор anotherstring
) на «zbc» таким образом, у dict есть два ключа, "zbc" и "zbc" ...
Одним из решений этой странности было бы то, что всякий раз, когда вы присваиваете строку идентификатору (или используете ее как ключ dict), она копирует строку с 0x1 по 0x2.
Это предотвращает вышесказанное, но что если у вас есть строка, которая требует 200 МБ памяти?
a = "really, really long string [...]"
b = a
Вдруг ваш скрипт занимает 400 МБ памяти? Это не очень хорошо.
Как насчет того, чтобы мы указывали на тот же адрес памяти, пока не изменим его? Копировать при записи . Проблема в том, что это может быть довольно сложно сделать ..
Вот тут и приходит неизменность. Вместо того, чтобы требовать от метода .replace()
скопировать строку из памяти в новый адрес, затем изменить ее и вернуть. Мы просто делаем все строки неизменяемыми, и поэтому функция должна создать новая строка для возврата. Это объясняет следующий код:
a = "abc"
b = a.replace("a", "z")
И доказано:
>>> a = 'abc'
>>> b = a
>>> id(a) == id(b)
True
>>> b = b.replace("a", "z")
>>> id(a) == id(b)
False
(функция id()
возвращает адрес памяти объекта)