Инициализация 2D-списков в Python: как сделать глубокие копии каждой строки?

Предположим, что я хочу инициализировать 2D-список Python со всеми 0, я бы сделал что-то вроде:

test = [[0.0] * 10] * 10 

Затем я начинаю изменять значения в первом списке …

 test[0][0] = 1.0 

Но это влияет на первый элемент списка ALL по какой-либо причине:

 print test [[1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]] 

Что с этим происходит? Почему он делает глубокую копию внутреннего списка, но неглубокую копию внешнего списка?

Выполнение [[0.0] * 10] * 10 фактически создает несколько копий одного и того же списка, поэтому их изменение будет влиять на все из них:

 >>> test = [[0.0] * 10] * 10 >>> [id(x) for x in test] #see all IDs are same [3065020524L, 3065020524L, 3065020524L, 3065020524L, 3065020524L, 3065020524L, 3065020524L, 3065020524L, 3065020524L, 3065020524L] 

Попробуй это:

 >>> test = [[0.0]*10 for _ in xrange(10)] >>> test[0][0] = 1.0 >>> test [[1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]] 

Целые числа / float неизменяемы, а списки изменяемы:

 >>> x = y = [] >>> x is y # Both point to the same object True >>> x.append(1) # list.extend modifies a list in-place >>> x,y # both references to [] can see the modification ([1], [1]) >>> x = y = 1 >>> x is y #both points to the same object True >>> x+=1 # only x gets modified, it now points to a new object 2 >>> x,y # y still points to the same object 1 (2, 1) 

Тест списка содержит несколько итераций одного и того же списка, поэтому изменение одного (как вы делаете, переназначив первый элемент test[0] ) отражается во всех остальных. Попробуйте это вместо этого:

 [[0.0]*10 for _ in xrange(10)] # or `range` in Python 3.x 

Конечно, вам не нужно было об этом беспокоиться, если бы все, что у вас было, было [0.0] * 10 , так как это создает список ints, ни один из которых никогда не может мутировать. Списки, с другой стороны, действительно изменяемы.