comportamiento inesperado de listas anidadas en python

Tengo una lista anidada llamada basic y quiero cambiar una de sus entradas. Yo había asumido el siguiente comportamiento:

 expected = [ [9],[0] ] unexpected = [ [9],[9] ] basic = [ [0],[0] ] basic[0][0] = 9 print(basic == expected) # this is true 

Sin embargo, una ligera modificación da un resultado sorprendente:

 l = [0] modified = [ l, l ] modified[0][0] = 9 print(modified == expected) # this is false print(modified == unexpected) # this is true 

Si su lista se define de la segunda forma, la asignación establece la columna completa en 9.

¿Es este comportamiento por diseño? Si es así, ¿por qué? No puedo encontrar nada en la documentación al respecto.

En tu primer ejemplo:

 basic = [ [0],[0] ] 

ha creado un objeto de lista que contiene dos objetos de lista diferentes. Puedes ver que son objetos diferentes a través de id() o identidad:

 assert id(basic[0]) != id(basic[1]) assert basic[0] is not basic[1] 

En tu segundo ejemplo:

 l = [0] modified = [ l, l ] 

ha colocado el mismo objeto de lista en otra lista dos veces. Las dos indicaciones de la lista se refieren al mismo objeto:

 assert id(basic[0]) == id(basic[1]) assert basic[0] is basic[1] 

Entonces sí. Así es como funcionan las variables (y los objetos a los que apuntan) en Python.

Para obtener el comportamiento esperado, necesita crear objetos de lista separados:

 modified = [ l.copy(), l.copy() ]