2015-04-22 15 views
6

Ho il seguente codice e variabili, e voglio trovare ciò che le variabili a, a1, a2, b, b1 e b2 si riferiscono a dopo l'esecuzione del codice.Riassegnazione variabili in pitone

def do_something(a, b): 
    a.insert(0, "z") 
    b = ["z"] + b 

a = ["a", "b", "c"] 
a1 = a 
a2 = a[:] 
b = ["a", "b", "c"] 
b1 = b 
b2 = b[:] 

do_something(a, b) 

Il mio tentativo di soluzione è la seguente:

a = ["z", "a", "b", "c"] 
a1 = ["a", "b", "c"] 
a2 = ["a", "b", "c"] 
b = ["z" "a", "b", "c"] 
b1 = ["a", "b", "c"] 
b2 = ["a", "b", "c"] 

Ma la soluzione reale è:

a = ["z", "a", "b", "c"] 
a1 = ["z", "a", "b", "c"] 
a2 = ["a", "b", "c"] 
b = ["a", "b", "c"] 
b1 = ["a", "b", "c"] 
b2 = ["a", "b", "c"] 

Qualcuno mi può camminare attraverso il mio errore?

+0

A che punto trovi/stampi i valori di tutte le variabili? Forse questo ha qualcosa a che fare con lo scope – Totem

+2

Penso che per "la mia soluzione tentata" intendi "quello che mi aspetto" ... è corretto? Ciò potrebbe chiarire una certa confusione. – Ajean

+2

Leggere [questo] (http: // stackoverflow.it/questions/1132941/least-astonishment-in-python-the-mutable-default-argument) può aiutare a capire perché questo è successo – Anzel

risposta

6

Ok, puoi pensare alle variabili in Python come riferimenti. Quando si esegue:

a1 = a 

Sia a1 e a sono riferimenti allo stesso oggetto, quindi se si modifica l'oggetto puntato da a vedrete i cambiamenti nel a1, perché - sorpresa - sono lo stesso oggetto (e il metodo list.insert modifica l'elenco in posizione).

Ma quando lo fai:

a2 = a[:] 

Poi a2 è un nuovo list esempio, e quando si modificano a non sta modificando a2.

Il risultato della + dell'operatore per gli elenchi è una nuova lista, in modo che quando si fa:

b = ['z'] + b 

si sta assegnando un nuovo elenco di b invece di mutazione b sul posto, come si farebbe con b.insert('z') . Ora b punta a un nuovo oggetto mentre b1 fa ancora riferimento al vecchio valore di b.

Ma gli ambiti possono essere ancora più complicati: è possibile visualizzare l'ambito che racchiude da una funzione, ma se si assegna una variabile all'interno della funzione, non verrà modificata la variabile con lo stesso nome nell'accludere (o globale, o built-in), creerà una variabile con questo nome nello scope locale. Questo è il motivo per cui non è stato modificato b - beh, non del tutto, il parametro che passa in Python è un'operazione di assegnazione, quindi b è già una variabile locale quando c'è un parametro chiamato b - ma provando a mutare una variabile definita nel campo di applicazione si porta a un problema simile A proposito, è una cattiva pratica fare affidamento su variabili dall'ambito di inclusione, a meno che non siano costanti a livello di modulo (tradizionalmente sono denominate in stile ALL_UPPERCASE e non si suppone che le si debba modificare). Se è necessario il valore all'interno della funzione, passarlo come parametro, e si desidera modificare il valore della variabile nel campo di applicazione che racchiude, restituire il valore e assegnare il valore restituito c'è:

def do_something(a, b): 
    a.insert(0, "z") # mutates a in-place 
    return ["z"] + b 

b = do_something(a, b) 
+2

, vale la pena ricordare che 'b' in' do_something' è stato riassegnato localmente, in modo che non cambi il valore globale 'b'. – Anzel

+2

Il valore di 'b' calcolato in' do_something() 'è locale alla funzione e viene gettato via quando termina quella funzione. Nessuna delle variabili globali 'b',' b1' o 'b2' viene toccata dalla funzione. – kindall

+0

grazie ragazzi, buona cattura. –