Python – Lista dinámica anidada

Así que estoy tratando de generar una lista anidada en Python basada en un ancho y una altura. Esto es lo que tengo hasta ahora:

width = 4 height = 5 row = [None]*width map = [row]*height 

Ahora, esto obviamente no está del todo bien. Cuando se imprime se ve bien:

 [[None, None, None, None], [None, None, None, None], [None, None, None, None], [None, None, None, None], [None, None, None, None]] 

Pero intentando asignar un valor a una posición como esta:

 map[2][3] = 'foo' 

Yo obtengo:

 [[None, None, None, 'foo'], [None, None, None, 'foo'], [None, None, None, 'foo'], [None, None, None, 'foo'], [None, None, None, 'foo']] 

Claramente, esto sucede porque cada sub-lista en realidad solo hace referencia al mismo objeto, fila, por lo que cambiar uno, los cambia a todos. ¡Así que esto es lo más cercano que tengo!

¿Cómo puedo generar dinámicamente una lista anidada? ¡Gracias!

Cuando haces [row]*height , terminas con el mismo objeto de lista en cada fila. La referencia de la matriz de row se repite en cada fila, lo que significa que cada fila apunta al mismo objeto de lista. Por lo tanto, la modificación de una fila en realidad modifica todas las filas.

Eche un vistazo a lo que sucede cuando imprime el id() para cada fila. ¡Todos son iguales!

 >>> grid = [[None] * width] * height >>> [id(row) for row in grid] [148014860, 148014860, 148014860, 148014860, 148014860] 

Puede hacer que Python genere listas separadas pero idénticas para cada fila utilizando una lista de comprensión. Cuando utilice [rowexpr for i in xrange(height)] , rowexpr se evaluará una vez por fila. El truco entonces es usar una expresión que dé como resultado una lista única cada vez que se evalúe.

Esto tendrá más sentido si lo ves en acción:

 >>> grid = [[None] * width for i in xrange(height)] >>> grid[2][3] = 'foo' >>> grid [[None, None, None, None], [None, None, None, None], [None, None, None, 'foo'], [None, None, None, None], [None, None, None, None]] 

Cada vez que se evalúa [None] * width genera una nueva lista.

 >>> [id(row) for row in grid] [148016172, 148015212, 148016236, 148016108, 148016332] 

Yo uso algo como esto:

 w = 5 h = 5 map = [] for i in range(h): row = [] for j in range(w): row.append(None) map.append(row) print map map[2][3] = 'foo' print map