2012-05-25 3 views
7

Sto lavorando attraverso Udacity e Dave Evans ha introdotto un esercizio sulla proprietà di elencoPerché l'operatore + non modifica un elenco mentre .append()?

list1 = [1,2,3,4] 
list2 = [1,2,3,4] 

list1=list1+[6] 
print(list1) 
list2.append(6) 
print(list2) 

list1 = [1,2,3,4] 
list2 = [1,2,3,4] 

def proc(mylist): 
    mylist = mylist + [6] 

def proc2(mylist): 
    mylist.append(6) 

# Can you explain the results given by the four print statements below? Remove 
# the hashes # and run the code to check. 

print (list1) 
proc(list1) 
print (list1) 

print (list2) 
proc2(list2) 
print (list2) 

L'uscita è

[1, 2, 3, 4, 6] 
[1, 2, 3, 4, 6] 
[1, 2, 3, 4] 
[1, 2, 3, 4] 
[1, 2, 3, 4] 
[1, 2, 3, 4, 6] 

Così in una funzione l'aggiunta di un 6 al set, ma non mostra lo fa quando non in una funzione?

risposta

15

Quindi in una funzione l'aggiunta di un 6 al set non viene mostrata ma lo fa quando non è in una funzione?

No, non è quello che succede.

Ciò che accade è che, quando si esegue mylist = mylist + [6], si sta effettivamente creando un elenco completamente nuovo e lo si inserisce nella variabile locale mylist. Questa variabile mylist scomparirà dopo l'esecuzione della funzione e anche l'elenco appena creato svanirà.

OTOH quando si esegue mylist.append(6) non si crea un nuovo elenco. Si ottiene l'elenco già nella variabile mylist e si aggiunge un nuovo elemento a questo stesso elenco. Il risultato è che la lista (indicata anche da list2) verrà modificata automaticamente. La variabile mylist scomparirà di nuovo, ma in questo caso è stato modificato l'elenco originale.

Vediamo se una spiegazione più visiva può aiutare :)

Cosa succede quando si chiama proc()

Quando si scrive list1 = [1, 2, 3, 4, 5] si sta creando un nuovo oggetto lista (sul lato destro delle pari firmare) e creare una nuova variabile, list1, che punterà a questo oggetto.

Creating new list instance and global variable

Poi, quando si chiama proc(), si crea un altro nuova variabile, mylist, e dal momento che si passa list1 come parametro, mylist punterà allo stesso oggetto:

Calling method creates local variable

Tuttavia , l'operazione mylist + [6]crea un intero nuovo oggetto elenco il cui contenuto è il contenuto dell'oggetto indicato da mylist più il contenuto del seguente oggetto elenco, ovvero [6]. Dal momento che si attribuiscono questo nuovo oggetto mylist, il nostro scenario cambia un po 'e mylist non punta allo stesso oggetto puntato da list1 più:

mylist points to new list object

Quello che non ho detto è che mylist è una variabile locale : scomparirà dopo la fine della funzione proc(). Così, quando l'esecuzione proc() conclusa, il mylist è andato:

mylist is gone

Da altri punti variabile all'oggetto generato da mylist + [6], esso scompare anche (poiché il garbage collector * lo ritirerà):

GC collects the list

noti che, alla fine, dell'oggetto puntato dal list1 non viene modificata.

Cosa succede quando si chiama proc2()

Tutto cambia quando si chiama proc2(). In un primo momento, è la stessa cosa: si crea un elenco ...

Creating new list instance and global variable

... e passare come parametro ad una funzione, che genererà una variabile locale:

Calling method creates local variable

Tuttavia, anziché utilizzare l'operatore di concatenazione + che genera un nuovo elenco, si applica il metodo append() all'elenco esistente. Il metodo append()non crea un nuovo oggetto; invece, esso _changes quella esistente:

Appending a value to a list

Dopo la fine della funzione, la variabile locale scompare, ma l'oggetto originale puntato per esso e per list1 saranno già alterata:

It is still altered

Poiché è ancora puntato da list1, l'elenco originale non viene distrutto.

EDIT: se si vuole dare un'occhiata a tutta questa roba accadendo davanti ai tuoi occhi basta andare a this radically amazing simulator:

enter image description here

* Se non si sa che cosa è garbage collector. .. beh, scoprirai subito dopo aver capito la tua domanda.

+5

C'è anche un buon [servizio] (http://people.csail.mit.edu/pgbovine/python/tutor.html#mode=edit) per fare il codice python passo passo e osservare tutte le variabili nel browser! Molto vicino a quello che hai scritto, @brandizzi – stalk

+0

+1 per un così bel disegno .. – gsagrawal

+0

@stalk Non conoscevo questo servizio. è semplicemente fantastico! Grazie! – brandizzi

2

Di solito, nel primo caso in funzione proc si sarebbe solo in grado di modificare l'elenco globale mediante cessione se dichiarato

global mylist 

prima e non ha superato mylist come parametro. Tuttavia, in questo caso verrà visualizzato un messaggio di errore che mylist è globale e locale: name 'mylist' is local and global. Quello che succede in proc è che viene creato un elenco locale quando l'assegnazione ha luogo. Poiché le variabili locali scompaiono al termine della funzione, l'effetto di eventuali modifiche all'elenco locale non viene propagato al resto del programma quando viene stampato successivamente.

Ma nella seconda funzione proc2 sei modificando l'elenco aggiungendo anziché assegnare ad esso, in modo che la parola chiave global non è richiesto e modifiche alla lista spettacolo altrove.

3

Le variabili in python possono sempre essere pensate come riferimenti. Quando si chiama una funzione con un argomento, si passa a un riferimento ai dati effettivi.

Quando si utilizza l'operatore di assegnazione (=), si assegna tale nome per fare riferimento a un oggetto completamente nuovo. Quindi, mylist = mylist + [6] crea un nuovo elenco contenente i vecchi contenuti di mylist, nonché 6 e assegna la variabile mylist per fare riferimento al nuovo elenco. list1 continua a puntare alla vecchia lista, quindi non cambia nulla.

D'altra parte, quando si utilizza .append, questo in realtà aggiunge un elemento all'elenco a cui fa riferimento la variabile - non assegna nulla di nuovo alla variabile. Quindi la tua seconda funzione modifica l'elenco a cui si riferisce l'elenco2.

0

Questo, in una forma o nell'altra, è una domanda molto comune. Ho preso una bacchetta spiegando il parametro Python passandomi allo a couple days ago. Fondamentalmente, uno di questi crea una nuova lista e l'altra modifica quella esistente. In quest'ultimo caso, tutte le variabili che si riferiscono alla lista "vedono" la modifica perché è sempre lo stesso oggetto.

0

Nella terza riga, l'avete fatto questo

list1=list1+[6] 

Così, quando hai fatto il sotto dopo la linea di cui sopra,

print (list1) 

che stampato lista1 che si è creato alla procedura di partenza e proc che aggiunge list1 + [6] che sta creando una nuova lista all'interno della funzione proc. Dove come quando stai accodando [6], non stai creando una nuova lista, piuttosto stai aggiungendo una lista ad una lista già esistente.

Ma, tieni a mente. In linea 7, è ancora una volta creato l'elenco

list1 = [1,2,3,4] 

Ora si voleva stampare il list1 chiamando esplicitamente, che stampare il lista1 che si reinizializzata ancora una volta, ma non quella precedente.

0

Oltre alle risposte esaurienti già date, è anche la pena di essere consapevole del fatto che se si desidera che la stessa sintassi cercando, come:

mylist = mylist + [6] 

...ma non vuole rinunciare alla lista da aggiornare "a posto", si può fare:

mylist += [6] 

Il che, mentre sembra che avrebbe fatto la stessa cosa come la prima versione, è realtà lo stesso:

mylist.extend([6]) 

(si noti che extend prende il contenuto di un iterabile e aggiunge uno per uno, mentre append prende tutto ciò che è dato e aggiunge che come un unico elemento. Vedere append vs. extend per una spiegazione completa.)