Изменчивый и неизменный в Python - PullRequest
5 голосов
/ 09 мая 2019

Я новичок в Python и пытаюсь понять разницу между изменяемыми и неизменяемыми объектами.Одним из изменяемых типов в Python является список.Допустим, L = [1,2,3], тогда у L есть идентификатор, который указывает на объект [1,2,3].Если содержимое [1,2,3] изменено, тогда L все еще сохраняет тот же идентификатор.Другими словами, L все еще ассоциируется с тем же объектом, даже если размер и содержание объекта были изменены.

С неизменными объектами, я понимаю, что изменение объекта не допускается.Следовательно, если переменная переназначается с новым значением, то эта переменная связывается с новым объектом с другим идентификатором.Я ожидаю, что строка будет вести себя аналогичным образом.Тем не менее я попытался изменить строку, но идентификатор строки не изменился.

string = "blue"
for i in range(10):
    string = string + str(i)
    print("string id after {}th iteration: {}".format(i,id(string)))


string id after 0th iteration: 46958272
string id after 1th iteration: 46958272
string id after 2th iteration: 46958272
string id after 3th iteration: 47077400
string id after 4th iteration: 47077400
string id after 5th iteration: 47077400
string id after 6th iteration: 47077400
string id after 7th iteration: 47077400
string id after 8th iteration: 47077400
string id after 9th iteration: 47077400

1 Ответ

2 голосов
/ 09 мая 2019

Вы действительно не должны видеть один и тот же идентификатор дважды в строке, но CPython имеет оптимизацию для конкатенации строк с +, которая не совсем подчиняется всем правилам, которые должны.

Когда CPython видит операцию в форме x = x + something или x += something, если x ссылается на строку и x содержит ссылку только на эту строку, то CPython будет увеличивать строка с realloc вместо создания нового строкового объекта. В зависимости от деталей доступной памяти, realloc может изменять размер выделенной памяти на месте или выделять новую память. Если он изменяет размер выделения, id объекта остается неизменным. Вы можете увидеть реализацию в unicode_concatenate в Python/ceval.c.

Эта оптимизация в основном в порядке, поскольку проверка refcount гарантирует, что она ведет себя в основном , как если бы строки были действительно неизменяемыми и была создана новая строка. Однако в x = x + stuff старая строка и новая строка должны иметь кратковременное время жизни, потому что новая строка должна появиться до того, как присваивание завершит время жизни старой строки, поэтому должно невозможно, чтобы значения идентификаторов были равны.

id - это один из немногих способов, которым оптимизация заметно отличается от того, если не произошло строковой мутации. Разработчики языка, похоже, решили, что с этим все в порядке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...