Когда вы
lst += ["42"]
Вы мутируют lst
и добавлением "42" в конце. Но когда вы говорите,
lst = lst + ["42"]
Вы создаете новый список с lst
и "42"
и назначая ссылку нового списка lst
. Попробуйте эту программу, чтобы понять это лучше.
lst = ["1"]
print(id(lst))
lst += ["2"]
print(id(lst))
lst = lst + ["3"]
print(id(lst))
Первые два идентификатора будут такими же, но последний будет отличаться. Потому что новый список создан, и lst
теперь указывает на этот новый список.
Не зная разницы между этими двумя будет создавать проблемы, когда вы передаете список в качестве параметра функции и добавление элемента к нему, внутри функции, как этот
def mutate(myList):
myList = myList + ["2"] # WRONG way of doing the mutation
tList = ["1"]
mutate(tList)
print(tList)
вы все равно получите ['1']
, но если вы действительно хотите, чтобы мутировать myList
, вы могли бы сделать, как этот
def mutate(myList):
myList += ["2"] # Or using append function
tList = ["1"]
mutate(tList)
print(tList)
напечатает ['1', '2']
Вы знаете, знаете ли, что определение языка Python * гарантирует *, что идентификатор изменится, когда вы выполните lst = lst + ["3"] ', или если это осталось для реализации? Я спрашиваю, потому что в принципе реализация Python с подсчетом ссылок может заметить, что 'lst' имеет refcount 1 в начале этой операции и получает обратно свой единственный реферер, и поэтому в качестве оптимизации требуется повторно использовать объект. Конечно, он может повторно использовать базовую память, используемую для массива, но мне интересно, позволяет ли этот язык повторно использовать сам «список». –
@SteveJessop Насколько я знаю, реализация 'id' зависит от реализации python. Но, в CPython, я точно знаю, что 'id' изменится, когда мы сделаем эту операцию. Потому что в CPython 'id' возвращает адрес памяти объекта. – thefourtheye
С гипотетической оптимизацией, описанной выше, адрес нового списка будет таким же, как старый. Таким образом, причина, по которой идентификатор изменяется на CPython, заключается не в том, что CPython использует адрес как id, а в том, что он не выполняет оптимизацию. 'id' должен возвращать разные значения для разных объектов, мой вопрос заключается в том, разрешена ли реализация Python, чтобы дать новому объекту тот же адрес, что и старый объект, который был уничтожен в том же самом заявлении (потому что его refcount достигает 0). –