operatore moltiplicare applicato all'elenco (struttura dati)
-
13-09-2019 - |
Domanda
Come pensare come un informatico che è un testo introduttivo per "programmazione Python" .
Ci tengo a precisare il comportamento dell'operatore si moltiplicano (*
), quando applicato alle liste.
Si consideri la funzione 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
L'uscita effettiva è
[[0, 7], [0, 7], [0, 7], [0, 7]]
La versione corretta di make_matrix è:
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
Il motivo per cui prima versione di make_matrix non riesce (come spiegato nel libro al 9,8) è che
... ogni riga è un alias delle altre righe ...
Mi chiedo perché
[[0] * columns] * rows
cause ... ogni riga è un alias delle altre righe ...
, ma non
[[0] * columns]
vale a dire. perché ogni [0]
fila non è un alias di altro elemento fila.
Soluzione
tutto in Python sono oggetti, e pitone non fa mai copie a meno che non esplicitamente chiesto di farlo.
Quando si esegue
innerList = [0] * 10
si crea una lista con 10 elementi, tutti loro riferendosi allo stesso oggetto int
0
.
Dato che gli oggetti interi sono immutabile , quando si esegue
innerList[1] = 15
Si sta modificando il secondo elemento della lista in modo che si riferisce ad un altro intero 15
. Che funziona sempre a causa di int
oggetti immutabilità.
Ecco perché
outerList = innerList * 5
creerà un oggetto list
con 5 elementi, ognuno è un riferimento a stesso innerList
come sopra. Ma dal momento che gli oggetti list
sono mutevole :
outerList[2].append('something')
è lo stesso:
innerList.append('something')
Perché sono due riferimenti al stesso oggetto list
. Così l'elemento finisce in quel singolo list
. Sembra essere duplicato, ma il fatto è che c'è un solo oggetto list
, e molti riferimenti ad esso.
Al contrario se si fa
outerList[1] = outerList[1] + ['something']
Qui si sono Creazione di altro oggetto list
(usando +
con gli elenchi è una copia esplicito), e l'assegnazione di un riferimento ad esso nella seconda posizione di outerList
. Se "aggiungere" l'elemento in questo modo (in realtà non aggiungendo, ma la creazione di un altro elenco), innerList
sarà inalterato.
Altri suggerimenti
elenchi non sono primitivi, vengono passati per riferimento. Una copia di una lista è un puntatore a un elenco (in gergo C). Tutto ciò che fate alla lista accade a tutte le copie della lista e le copie del suo contenuto a meno che non si fa una copia.
[[0] * columns] * rows
Ops, abbiamo appena fatto una grande lista di puntatori a [0]. Modificare uno e li tutti i cambiamenti.
I numeri interi non sono passati per riferimento, sono veramente copiati, quindi [0] * Contenuti sta davvero facendo un sacco di nuovi 0 e aggiungendole alla lista.