Perché le tuple possono contenere elementi mutabili?


178

Se una tupla è immutabile, allora perché può contenere elementi mutabili?

Apparentemente è una contraddizione che quando un elemento mutabile come un elenco viene modificato, la tupla a cui appartiene continua a essere immutabile.

Risposte:


205

Questa è un'ottima domanda.

L'intuizione chiave è che le tuple non hanno modo di sapere se gli oggetti al loro interno sono mutabili. L'unica cosa che rende mutevole un oggetto è avere un metodo che alteri i suoi dati. In generale, non c'è modo di rilevarlo.

Un'altra intuizione è che i contenitori di Python in realtà non contengono nulla. Al contrario, mantengono riferimenti ad altri oggetti. Allo stesso modo, le variabili di Python non sono come variabili nei linguaggi compilati; invece i nomi delle variabili sono solo chiavi in ​​un dizionario dello spazio dei nomi in cui sono associati a un oggetto corrispondente. Ned Batchhelder lo spiega bene nel suo post sul blog . Ad ogni modo, gli oggetti conoscono solo il loro conteggio di riferimento; non sanno quali siano quei riferimenti (variabili, container o interni di Python).

Insieme, queste due intuizioni spiegano il tuo mistero (perché una tupla immutabile "contenente" un elenco sembra cambiare quando cambia l'elenco sottostante). In effetti, la tupla non è cambiata (ha ancora gli stessi riferimenti ad altri oggetti che ha fatto prima). La tupla non poteva cambiare (perché non aveva metodi di mutazione). Quando l'elenco è cambiato, la tupla non è stata informata della modifica (l'elenco non sa se a cui fa riferimento una variabile, una tupla o un altro elenco).

Mentre siamo sull'argomento, ecco alcuni altri pensieri per aiutarti a completare il tuo modello mentale di cosa sono le tuple, come funzionano e il loro uso previsto:

  1. Le tuple sono caratterizzate meno dalla loro immutabilità e più dal loro scopo previsto.
    Le tuple sono il modo in cui Python raccoglie informazioni eterogenee sotto lo stesso tetto. Ad esempio, s = ('www.python.org', 80) riunisce una stringa e un numero in modo che la coppia host / porta possa essere passata come socket, un oggetto composito. Visto in quella luce, è perfettamente ragionevole avere componenti mutabili.

  2. L'immutabilità va di pari passo con un'altra proprietà, l' hashbility . L'hashbility non è una proprietà assoluta. Se uno dei componenti della tupla non è hash, anche la tupla complessiva non è hash. Ad esempio, t = ('red', [10, 20, 30])non è cancellabile.

L'ultimo esempio mostra una 2 tupla che contiene una stringa e un elenco. La tupla stessa non è modificabile (cioè non ha alcun metodo che per cambiarne il contenuto). Allo stesso modo, la stringa è immutabile perché le stringhe non hanno alcun metodo di mutazione. L'oggetto elenco ha metodi di mutazione, quindi può essere modificato. Ciò dimostra che la mutabilità è una proprietà di un tipo di oggetto - alcuni oggetti hanno metodi di mutazione e altri no. Questo non cambia solo perché gli oggetti sono nidificati.

Ricorda due cose. Innanzitutto, l'immutabilità non è magica - è semplicemente l'assenza di metodi mutanti. In secondo luogo, gli oggetti non sanno a quali variabili o contenitori si riferiscono a loro - conoscono solo il conteggio dei riferimenti.

Spero che questo ti sia stato utile :-)


Non è sbagliato "le tuple non hanno modo di sapere se gli oggetti al loro interno sono mutabili". Siamo in grado di rilevare se il riferimento implementa un metodo hash, quindi è immutabile. Come farebbe un dic o un set. Non sarebbe più una decisione progettuale per ciò che le tuple dovrebbero essere?
garg10may

@ garg10may 1) L'hashibility non è facile da rilevare senza chiamare hash()perché tutto ciò che eredita da object () è hash e quindi le sottoclassi devono disattivare esplicitamente l'hash. 2) L'hashibility non garantisce l'immutabilità: è facile fare esempi di oggetti lavabili che sono mutabili. 3) Le tuple, come la maggior parte dei contenitori in Python, hanno solo riferimenti all'oggetto sottostante - non hanno il dovere di ispezionarli e fare inferenze su di essi.
Raymond Hettinger,

171

Questo perché le tuple non contengono elenchi, stringhe o numeri. Contengono riferimenti ad altri oggetti . 1 L'incapacità di cambiare la sequenza di riferimenti contenuti in una tupla non significa che non puoi mutare gli oggetti associati a quei riferimenti. 2

1. Oggetti, valori e tipi (vedi: dal secondo all'ultimo paragrafo)
2. La gerarchia dei tipi standard (vedi: "Sequenze immutabili")


8
C'è un'ambiguità nella domanda. Questa risposta spiega perché è possibile che le tuple contengano oggetti mutabili. Non spiega perché le tuple siano state progettate per contenere oggetti mutabili. Penso che quest'ultima sia la domanda più pertinente.
mittente

16

Prima di tutto, la parola "immutabile" può significare molte cose diverse per persone diverse. Mi piace particolarmente come Eric Lippert abbia classificato l'immutabilità nel suo post sul blog . Lì, elenca questi tipi di immutabilità:

  • Immutabilità del realio-trulio
  • Immutabilità scrivibile una volta
  • Immutabilità dei ghiaccioli
  • Immutabilità superficiale vs profonda
  • Facciate immutabili
  • Immutabilità osservativa

Questi possono essere combinati in vari modi per rendere ancora più tipi di immutabilità, e sono sicuro che ne esistano di più. Il tipo di immutabilità che sembra interessato all'immutabilità profonda (anche conosciuta come transitiva), in cui gli oggetti immutabili possono contenere solo altri oggetti immutabili.

Il punto chiave di ciò è che l'immutabilità profonda è solo uno dei tanti, molti tipi di immutabilità. Puoi adottare qualunque tipo preferisci, purché tu sia consapevole che la tua nozione di "immutabile" probabilmente differisce dalla nozione di "immutabile" di qualcun altro.


Che tipo di immutabilità hanno le tuple Python?
qazwsx,

3
Le tuple di Python hanno immutabilità superficiale (alias non transitiva).
Ken Wayne VanderLinde

16

A quanto ho capito, questa domanda deve essere riformulata come una domanda sulle decisioni di progettazione: perché i progettisti di Python hanno scelto di creare un tipo di sequenza immutabile che può contenere oggetti mutabili?

Per rispondere a questa domanda, dobbiamo pensare allo scopo delle tuple : servono come sequenze veloci e generiche . Con questo in mente, diventa abbastanza ovvio il motivo per cui le tuple sono immutabili ma possono contenere oggetti mutabili. Per dire:

  1. Le tuple sono veloci ed efficienti in termini di memoria: le tuple sono più veloci da creare rispetto agli elenchi perché sono immutabili. Immutabilità significa che le tuple possono essere create come costanti e caricate come tali, usando la piegatura costante . Significa anche che sono più veloci e più efficienti in termini di memoria da creare perché non c'è bisogno di sovrallocazione, ecc. Sono un po ' più lenti degli elenchi per l'accesso casuale agli oggetti, ma ancora più veloci per il disimballaggio (almeno sulla mia macchina). Se le tuple fossero mutevoli, non sarebbero così veloci per scopi come questi.

  2. Le tuple sono di uso generale : le tuple devono essere in grado di contenere qualsiasi tipo di oggetto. Sono abituati a fare (rapidamente) cose come elenchi di argomenti a lunghezza variabile (tramite l' *operatore nelle definizioni delle funzioni). Se le tuple non potessero contenere oggetti mutevoli, sarebbero inutili per cose come questa. Python dovrebbe usare le liste, che probabilmente rallenterebbero le cose e sarebbero sicuramente meno efficienti in termini di memoria.

Quindi vedi, per raggiungere il loro scopo, le tuple devono essere immutabili, ma devono anche essere in grado di contenere oggetti mutabili. Se i progettisti di Python volessero creare un oggetto immutabile che garantisca che anche tutti gli oggetti che "contiene" siano immutabili, dovrebbero creare un terzo tipo di sequenza. Il guadagno non vale la complessità aggiuntiva.


12

Non è possibile modificare i idsuoi elementi. Quindi conterrà sempre gli stessi articoli.

$ python
>>> t = (1, [2, 3])
>>> id(t[1])
12371368
>>> t[1].append(4)
>>> id(t[1])
12371368

Questa è la dimostrazione più appropriata degli esempi sopra. Tupla ha riferimenti a quegli oggetti che non cambiano, sebbene avere al massimo un componente mutabile renda inaffidabile l'intera tupla.
piepi,

5

Esco da un arto qui e dico che la parte rilevante qui è che mentre puoi cambiare il contenuto di un elenco, o lo stato di un oggetto, contenuto in una tupla, ciò che non puoi cambiare è che l'oggetto o la lista è lì. Se avessi qualcosa che dipendeva dalla cosa [3] come un elenco, anche se vuoto, allora potrei vedere che questo è utile.


3

Uno dei motivi è che in Python non esiste un modo generale per convertire un tipo mutabile in uno immutabile (vedere il PEP 351 respinto e la discussione collegata sul perché è stato rifiutato). Pertanto, sarebbe impossibile mettere vari tipi di oggetti in tuple se avesse questa limitazione, incluso praticamente qualsiasi oggetto non hash creato dall'utente.

L'unica ragione per cui dizionari e set hanno questa limitazione è che richiedono che gli oggetti siano hash, poiché sono implementati internamente come tabelle hash. Ma nota che, ironia della sorte, i dizionari e gli insiemi non sono immutabili (o cancellabili). Le tuple non usano l'hash di un oggetto, quindi la sua mutabilità non ha importanza.


2

Una tupla è immutabile nel senso che la tupla stessa non può espandersi o restringersi, non che tutti gli elementi contenuti sono immutabili. Altrimenti le tuple sono noiose.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.