Pregunta

Cómo pensar como un científico de la computación que es un texto introductorio de "programación Python" .

quiero aclarar el comportamiento del operador de multiplicar (*) cuando se aplica a las listas.

Considere la función make_matrix

def make_matrix(rows, columns):
"""
  >>> make_matrix(4, 2)
  [[0, 0], [0, 0], [0, 0], [0, 0]]
  >>> m = make_matrix(4, 2)
  >>> m[1][1] = 7
  >>> m
  [[0, 0], [0, 7], [0, 0], [0, 0]]
"""
return [[0] * columns] * rows

La salida real es

[[0, 7], [0, 7], [0, 7], [0, 7]]

La versión correcta de make_matrix es:

def make_matrix(rows, columns):
"""
  >>> make_matrix(3, 5)
  [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
  >>> make_matrix(4, 2)
  [[0, 0], [0, 0], [0, 0], [0, 0]]
  >>> m = make_matrix(4, 2)
  >>> m[1][1] = 7
  >>> m
  [[0, 0], [0, 7], [0, 0], [0, 0]]
"""
matrix = []
for row in range(rows):
    matrix += [[0] * columns]
return matrix

La razón por la primera versión de make_matrix falla (como se explica en el libro en 9.8) es que

... cada fila es un alias de las otras filas ...

Me pregunto por qué

[[0] * columns] * rows

... cada fila es un alias de las otras filas ...

pero no

[[0] * columns]

es decir. por qué cada [0] en una fila no es un alias de otro elemento fila.

¿Fue útil?

Solución

todo en Python son objetos, y Python no hace copias menos que explícitamente pidió que lo hiciera.

Al hacer

innerList = [0] * 10

se crea una lista con 10 elementos, todos ellos refiriéndose al mismo objeto int 0 .

Dado que los objetos son enteros inmutable , cuando lo hace

innerList[1] = 15

Está cambiando el segundo elemento de la lista para que se refiera a otro número entero 15 . Eso siempre funciona debido a int objetos inmutabilidad.

Es por eso

outerList = innerList * 5

creará un objeto list con 5 elementos, cada uno es una referencia a el mismo innerList al igual que anteriormente. Pero ya que los objetos son list mutable

outerList[2].append('something')

Es lo mismo que:

innerList.append('something')

Debido a que son dos referencias a la mismo objeto list . Por lo que el elemento termina en esa única list. Parece ser duplicado, pero el hecho es que no es sólo un objeto list, y muchas referencias a él.

Por el contrario si lo hace

outerList[1] = outerList[1] + ['something']

Aquí está Creación de otro objeto list (usando + con las listas es una copia explícita), y asignar una referencia a él en la segunda posición de outerList. Si "añadir" el elemento de esta manera (no es realmente añadiendo, pero la creación de otra lista), innerList no se verá afectada.

Otros consejos

listas no son primitivas, que se pasan por referencia. Una copia de una lista es un puntero a una lista (en C jerga). Cualquier cosa que haga a la lista pasa a todas las copias de la lista y las copias de su contenido a menos que haga una copia superficial.

[[0] * columns] * rows

Vaya, acabamos de hacer una gran lista de punteros a [0]. Cambiar una y cambia a todos.

Los enteros no se pasan por referencia, que realmente están copiados, por lo tanto, [0] * contenidos realmente está haciendo un montón de nuevas 0 y añadiéndolos a la lista.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top