Почему цикл for в python изменяет списки без ссылок? - PullRequest
1 голос
/ 16 декабря 2010

Я работаю над сценарием py, который читает строки из файла csv, манипулирует ими и выводит их обратно.Пока у меня работает преобразование csv в список.

Проблема, с которой я сталкиваюсь, заключается в том, что когда я перебираю временные списки, циклы for изменяют ВСЕ временные списки, а не только тот, который я хочу.Вот простой пример того, что я пытаюсь сказать.

>>> l = [['hi', 'ho'],['no', 'go']]
>>> t = []
>>> y = []
>>> 
>>> for row in l:
...     row[0] = '123'
...     y.append(row)
...     t.append(row)
... 
>>> y
[['123', 'ho'], ['123', 'go']]
>>> t
[['123', 'ho'], ['123', 'go']]

Так что вышеизложенное просто (надеюсь).(Давайте предположим, что я хочу заняться другими вещами, кроме копирования списка l. Просто хочу, чтобы все было просто).

Но теперь вот часть, которую я не получаю.

>>> z = []
>>> for row in y:
...     row[0] = 'xxxx'
...     z.append(row)
... 
>>> z
[['xxxx', 'ho'], ['xxxx', 'go']]
>>> t
[['xxxx', 'ho'], ['xxxx', 'go']]
>>> y
[['xxxx', 'ho'], ['xxxx', 'go']]

Когда я хочу изменить первую часть в подсписках и сохранить ее в новом списке 'z', он также изменяет список t!

Что здесь происходит? Указывают ли z, y и t на одну и ту же ячейку памяти?

Кроме того, что здесь происходит?:

>>> for rowx in y:
...     rowx[0] = 'x55x'
...     z.append(rowx)
... 
>>> z
[['xxxx', 'ho'], ['x55x', 'go'], ['x55x', 'go'], ['x55x', 'go']]
>>> t
[['xxxx', 'ho'], ['x55x', 'go']]
>>> y
[['xxxx', 'ho'], ['x55x', 'go']]

Как и в предыдущем вопросе, почему меняются y и t?

Заранее спасибо !!

Ответы [ 3 ]

7 голосов
/ 16 декабря 2010

Python не имеет ничего , но ссылок.row является ссылкой на фактический элемент в пределах l или y.Мутирование row изменяет этот элемент, а добавление его к другому объекту добавляет оригинальный элемент.

4 голосов
/ 16 декабря 2010

Ваши три списка разные, но между ними есть только два элемента:

>>> y[0] is t[0] is z[0]
True
>>> y[1] is t[1] is z[1]
True

Если оператор is сообщает, что ваши ссылки указывают на один и тот же объект, тогда изменения в объекте появятся независимо от того, какую ссылку вы используете.

Чтобы избежать этого, используйте модуль copy , если вы хотите скопировать элементы:

>>> import copy
>>> a = copy.deepcopy(y)
>>> a
[['xxxx', 'ho'], ['xxxx', 'go']]
>>> a[0] is y[0]
False
>>> a[0][0] = 'copy!'
>>> y
[['xxxx', 'ho'], ['xxxx', 'go']]
0 голосов
/ 16 декабря 2010

«Неужели z, y и t указывают на одну и ту же ячейку памяти?»

Нет, но z [0], y [0] и t [0] (хотя не называйте это ячейками памяти, это не C). Вы добавляете один и тот же список ['hi', 'ho'] к z, y и t. Так что это тот же список. Если вы не хотите, чтобы это был тот же список, вы должны сначала сделать копию.

...