python вопрос по спискам и ссылкам на них

stm8859064

есть список, хочу его скопировать и изменять копию. Использовал конструкцию list_copy=list[:], всегда работало, а тут встретил проблему:
>>> data=[[1],[2],[3]]
>>> test=data[:]
>>> for i in range(1,len(data:
... for j in range(len(data[i]:
... test[i][j]=0
...
>>> print data
[[1], [0], [0]]

т.е. начальные данные портятся. Почему так происходит?
если в цикле заменить data на test результат тот же
Python 2.7.2 (default, Oct 11 2012, 20:14:37)
[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin

Dasar

копируется только внешний массив, в виде копирования ссылок на внутренние массивы. соответственно, внутренние массивы в обоих случаях остаются одними и теми же

spitfire

http://docs.python.org/2/library/copy.html , по всей видимости.

yroslavasako

проблема решается сериализацией/десериализацией, если производительности не жалко

danilov

Используй глубокое копирование. Хотя если структура известна, быстрее будет руками

kedr1983

Как выше написали, используй библиотеку copy и функцию deepcopy.

>>> import copy
>>> data = [[1],[2],[3]]
>>> test = copy.copy(data) # По сути то же, что и test = data[:]
>>> id(data) == id(test) # Сравниваем ссылки на списки
False
>>> test[0][0] = 0
>>> data
[[0], [2], [3]]
>>> id(data[0]) == id(test[0]) # Сравниваем ссылки на элементы списков (вложенные списки)
True
>>> data = [[1],[2],[3]]
>>> test = copy.deepcopy(data) # Глубокое копирование
>>> test[0][0] = 0
>>> data
[[1], [2], [3]]
>>> test
[[0], [2], [3]]
>>> id(data[0]) == id(test[0]) # Сравниваем ссылки на вложенные списки
False

Update (11.07.2013 14:53): Осторожней при проверках малых чисел. Ссылки на переменные с малыми числами (между -5 и 256) могут совпадать из-за особенностей кеширования в Python.
Т.е. в примере выше id(data[1][0]) == id(test[1][0]) вернет True.

stm8859064

а как так красиво код раскрашивать?

kedr1983

[code=py]
Python code
[/code]
Оставить комментарий
Имя или ник:
Комментарий: