2013-05-02 15 views
72

Ho provato a utilizzare più incarichi come mostrato di seguito per inizializzare le variabili, ma mi sono confuso dal comportamento, mi aspetto di riassegnare separatamente la lista valori, intendo b [0] e c [0] uguale a 0 come prima.Python che assegna più variabili allo stesso valore? elenco comportamento

a=b=c=[0,3,5] 
a[0]=1 
print(a) 
print(b) 
print(c) 

risultato è: [1, 3, 5] [1, 3, 5] [1, 3, 5]

E 'corretto? cosa dovrei usare per un incarico multiplo? cosa c'è di diverso da questo?

d=e=f=3 
e=4 
print('f:',f) 
print('e:',e) 

risultato: ('f:', 3) ('e:', 4)

+2

Vuoi 'a',' b' e 'c,' puntare tutti allo stesso valore (in questo caso una lista), o vuoi 'a = 0',' b = 3', e 'c = 5'. In tal caso, vuoi 'a, b, c = [0,3,5]' o solo 'a, b, c = 0,3,5'. – chepner

risposta

169

se vieni a Python da una lingua in C/Java/etc. famiglia, potrebbe aiutarti a smettere di pensare a a come a una "variabile" e iniziare a pensarlo come un "nome".

a, b e c non sono variabili diverse con valori uguali; sono nomi diversi per lo stesso identico valore. Le variabili hanno tipi, identità, indirizzi e tutti i tipi di cose del genere.

I nomi non hanno nulla di tutto ciò. Valori fanno, ovviamente, e puoi avere molti nomi per lo stesso valore.

Se si dà Notorious B.I.G. un hot dog, * Biggie Smalls e Chris Wallace avere un hot dog. Se si modifica il primo elemento di a-1, i primi elementi di b e c sono 1.

Se vuoi sapere se due nomi sono nominare il medesimo oggetto, utilizzare l'operatore di is:

>>> a=b=c=[0,3,5] 
>>> a is b 
True 

è poi chiedere:

ciò che è diverso da questo?

d=e=f=3 
e=4 
print('f:',f) 
print('e:',e) 

Qui, si sta rebinding il nome e al valore 4. Ciò non ha alcun effetto sui nomi d e f in alcun modo.

Nella versione precedente, si assegnava a a[0], non a a. Quindi, dal punto di vista di a[0], stai riconciliando a[0], ma dal punto di vista di a, lo stai cambiando sul posto.

È possibile utilizzare la funzione id, che vi dà qualche numero univoco che rappresenta l'identità di un oggetto, per vedere esattamente quale oggetto è che, anche quando non si può fare is:

>>> a=b=c=[0,3,5] 
>>> id(a) 
4473392520 
>>> id(b) 
4473392520 
>>> id(a[0]) 
4297261120 
>>> id(b[0]) 
4297261120 

>>> a[0] = 1 
>>> id(a) 
4473392520 
>>> id(b) 
4473392520 
>>> id(a[0]) 
4297261216 
>>> id(b[0]) 
4297261216 

noti che a[0] ha cambiato da 4297261120 a 4297261216-ora è un nome per un valore diverso. E b[0] è ora anche un nome per quello stesso nuovo valore. Questo perché a e b stanno ancora denominando lo stesso oggetto.


Sotto le coperte, a[0]=1 è in realtà chiamare un metodo per l'oggetto lista. (È equivalente a a.__setitem__(0, 1).) Quindi, non è davvero ripetere nulla. È come chiamare my_object.set_something(1). Certo, probabilmente l'oggetto sta riconcordando un attributo di istanza per implementare questo metodo, ma questo non è ciò che è importante; l'importante è che non stai assegnando nulla, stai semplicemente mutando l'oggetto. Ed è lo stesso con a[0]=1.


user570826 chiesto:

Che cosa succede se abbiamo, a = b = c = 10

che è esattamente la stessa situazione a = b = c = [1, 2, 3]: avete tre nomi per lo stesso valore.

Ma in questo caso, il valore è uno int e int s sono immutabili. In entrambi i casi, è possibile riassociare a a un valore diverso (ad es., a = "Now I'm a string!"), ma non influirà sul valore originale, per cui saranno ancora disponibili i nomi b e c. La differenza è che con un elenco è possibile modificare il valore [1, 2, 3] in [1, 2, 3, 4] facendo, ad es., a.append(4); Dal momento che in realtà sta cambiando il valore che sono b e c, b sarà ora b [1, 2, 3, 4]. Non c'è modo di cambiare il valore 10 in qualcos'altro. 10 è 10 per sempre, proprio come Claudia il vampiro ha 5 anni (almeno fino a quando non sarà sostituita da Kirsten Dunst).


* Avvertenza: non fornire B.I.G. un hot dog. Gli zombie Gangsta Rap non dovrebbero mai essere nutriti dopo la mezzanotte.

+24

Una frase che fa riferimento a rappers, zombi e Gremlins? Vincere. – DSM

+0

Cosa succede se abbiamo 'a, a = b = c = 10;' e quando proviamo ad aggiornare il valore di b, ha effetto un altro? anche se ho controllato che i loro id sono uguali. – Clayton

+0

@ user570826: '10' è immutabile, ovvero non è possibile aggiornare il valore, quindi la tua domanda non ha senso. Puoi puntare a 'b' su un valore diverso, ma farlo non ha effetto su' a' e 'c', che puntano ancora al valore originale. La differenza che gli elenchi fanno è che sono mutabili, ad esempio, puoi "aggiungere" a una lista, o "lst [0] = 3', e questo aggiornerà il valore, che sarà visibile attraverso tutti i nomi per quel valore . – abarnert

3

Quello che vi serve è questo:

a, b, c = [0,3,5] # Unpack the list, now a, b, and c are ints 
a = 1    # `a` did equal 0, not [0,3,5] 
print(a) 
print(b) 
print(c) 
4

nel primo esempio a = b = c = [1, 2, 3] voi stanno davvero dicendo:

'a' is the same as 'b', is the same as 'c' and they are all [1, 2, 3] 

Se si desidera impostare 'a' uguale a 1, 'b' uguale a ' 2 'e' c 'uguale a 3, prova questo:

a, b, c = [1, 2, 3] 

print(a) 
--> 1 
print(b) 
--> 2 
print(c) 
--> 3 

Spero che questo aiuti!

12

Sì, questo è il comportamento previsto. a, bec sono tutti impostati come etichette per lo stesso elenco. Se vuoi tre diversi elenchi, devi assegnarli singolarmente. È possibile ripetere l'elenco esplicito, o utilizzare uno dei numerosi modi per copiare un elenco:

b = a[:] # this does a shallow copy, which is good enough for this case 
import copy 
c = copy.deepcopy(a) # this does a deep copy, which matters if the list contains mutable objects 

dichiarazioni di assegnazione in Python non copiare gli oggetti - si legano il nome ad un oggetto, e un oggetto può avere tante etichette quante ne hai impostate. Nella tua prima modifica, cambiando a [0], stai aggiornando un elemento della lista singola a cui a, b, c si riferiscono. Nel secondo, cambiando e, cambierai e diventerai un'etichetta per un oggetto diverso (4 invece di 3).

8

In python, tutto è un oggetto, anche tipi di variabili "semplici" (int, float, ecc.).

Quando si cambia un valore variabile, si cambia in realtà è puntatore, e se si mette a confronto tra due variabili E 'a confronto le loro puntatori. (Per essere chiari, il puntatore è l'indirizzo nella memoria fisica del computer in cui è memorizzata una variabile).

Di conseguenza, quando si modifica un valore di una variabile interna, si modifica il suo valore nella memoria e si influisce su tutte le variabili che puntano a questo indirizzo.

Per esempio, quando si esegue:

a = b = 5 

Ciò significa che A e B indica lo stesso indirizzo di memoria che contiene il valore 5, ma quando lo fai:

a = 6 

Non ha effetto b perché a è ora punta a un'altra locazione di memoria che contiene 6 e b punta ancora all'indirizzo di memoria che contiene 5.

Ma, quando si esegue:

a = b = [1,2,3] 

A e B, ancora una volta, punta alla stessa posizione, ma la differenza è che se si modifica l'uno dei valori della lista:

a[0] = 2 

Cambia il valore della memoria su cui è un punto, ma a è ancora punta allo stesso indirizzo di b, e come risultato cambia anche b.

+4

Questo è altamente fuorviante. I puntatori non sono certamente visibili a livello di Python, e almeno due delle quattro principali implementazioni (PyPy e Jython) non li usano nemmeno all'interno dell'implementazione. – abarnert

+1

Ti invitiamo a leggere ed esplorare gli interni di python e scoprirai che ogni variabile in python è in realtà un puntatore. –

+4

No. In _one implementation_ di Python (CPython), ogni variabile è un puntatore a un 'PyObject'. Questo non è vero in altre implementazioni come PyPy o Jython. (In effetti, non è nemmeno chiaro come dovrebbe essere vero, perché i linguaggi in cui sono scritte queste implementazioni non hanno nemmeno i puntatori.) – abarnert

8

È possibile utilizzare id(name) per verificare se due nomi rappresentano lo stesso oggetto:

>>> a = b = c = [0, 3, 5] 
>>> print(id(a), id(b), id(c)) 
46268488 46268488 46268488 

liste sono mutabili; significa che è possibile modificare il valore in atto senza creare un nuovo oggetto. Tuttavia, dipende da come si modifica il valore:

>>> a[0] = 1 
>>> print(id(a), id(b), id(c)) 
46268488 46268488 46268488 
>>> print(a, b, c) 
[1, 3, 5] [1, 3, 5] [1, 3, 5] 

Se si assegna un nuovo elenco di a, allora il suo id cambierà, in modo da non influenzare b e valori c s':

>>> a = [1, 8, 5] 
>>> print(id(a), id(b), id(c)) 
139423880 46268488 46268488 
>>> print(a, b, c) 
[1, 8, 5] [1, 3, 5] [1, 3, 5] 

interi sono immutabili, quindi non è possibile modificare il valore senza creare un nuovo oggetto:

>>> x = y = z = 1 
>>> print(id(x), id(y), id(z)) 
507081216 507081216 507081216 
>>> x = 2 
>>> print(id(x), id(y), id(z)) 
507081248 507081216 507081216 
>>> print(x, y, z) 
2 1 1 
+1

'id' non è necessariamente un percorso di memoria. Come [i documenti] (http://docs.python.org/2/library/functions.html#id) dicono, questo restituisce "l'identità ... un intero ... che è garantito essere unico e costante per questo oggetto durante il suo tutta la vita." CPython capita di usare l'indirizzo di memoria come 'id', ma altre implementazioni di Python potrebbero non farlo. PyPy, per esempio, non lo fa. E dire "due tag indicano la stessa posizione di memoria" è fuorviante per chiunque lo capisca in stile C. "Due nomi per lo stesso oggetto" è sia più preciso che meno fuorviante. – abarnert

+0

@abarnert Grazie per il chiarimento, ho aggiornato la risposta. – jurgenreza

2

Grazie a tutti per i vostri chiarimenti.

il codice che fa quello che mi serve potrebbe essere questo:

#test 
aux=[[0 for n in range(3)] for i in range(4)] 
print('aux:',aux) 
#initialization 
a,b,c,d=[[0 for n in range(3)] for i in range(4)] 
#changing values 
a[0]=1 
d[2]=5 
print('a:',a) 
print('b:',b) 
print('c:',c) 
print('d:',d) 

risultato: ('aux:', [[0, 0, 0], [0, 0, 0], [0 , 0, 0], [0, 0, 0]]) ('a:', [1, 0, 0]) ('b:', [0, 0, 0]) ('c: ', [0, 0, 0]) ('d:', [0, 0, 5])

saluti

18

tosse tosse

>>> a,b,c = (1,2,3) 
>>> a 
1 
>>> b 
2 
>>> c 
3 
>>> a,b,c = ({'test':'a'},{'test':'b'},{'test':'c'}) 
>>> a 
{'test': 'a'} 
>>> b 
{'test': 'b'} 
>>> c 
{'test': 'c'} 
>>> 
3

In poche parole, nel primo caso si assegnano più nomi a list. Solo una copia dell'elenco viene creata in memoria e tutti i nomi si riferiscono a tale posizione. Quindi la modifica dell'elenco utilizzando uno qualsiasi dei nomi modificherà effettivamente l'elenco in memoria.

Nel secondo caso, vengono create più copie dello stesso valore in memoria. Quindi ogni copia è indipendente l'una dall'altra.

Problemi correlati