2013-11-22 4 views
2

код A:Есть ли разница между двумя?

lst = [1, 2, 3] 
for i in range(10): 
    lst+= ["42"] 

код B:

lst = [1, 2, 3] 
for i in range(10): 
    lst = lst + ["42"] 

Я знаю, что выход то же самое, но есть разница в том, как эти два списка построены? Что происходит на самом деле?

ответ

5

Когда вы

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']

+0

Вы знаете, знаете ли, что определение языка Python * гарантирует *, что идентификатор изменится, когда вы выполните lst = lst + ["3"] ', или если это осталось для реализации? Я спрашиваю, потому что в принципе реализация Python с подсчетом ссылок может заметить, что 'lst' имеет refcount 1 в начале этой операции и получает обратно свой единственный реферер, и поэтому в качестве оптимизации требуется повторно использовать объект. Конечно, он может повторно использовать базовую память, используемую для массива, но мне интересно, позволяет ли этот язык повторно использовать сам «список». –

+0

@SteveJessop Насколько я знаю, реализация 'id' зависит от реализации python. Но, в CPython, я точно знаю, что 'id' изменится, когда мы сделаем эту операцию. Потому что в CPython 'id' возвращает адрес памяти объекта. – thefourtheye

+0

С гипотетической оптимизацией, описанной выше, адрес нового списка будет таким же, как старый. Таким образом, причина, по которой идентификатор изменяется на CPython, заключается не в том, что CPython использует адрес как id, а в том, что он не выполняет оптимизацию. 'id' должен возвращать разные значения для разных объектов, мой вопрос заключается в том, разрешена ли реализация Python, чтобы дать новому объекту тот же адрес, что и старый объект, который был уничтожен в том же самом заявлении (потому что его refcount достигает 0). –

Смежные вопросы