Tipi immutabili vs mutabili


186

Sono confuso su cosa sia un tipo immutabile. So che l' floatoggetto è considerato immutabile, con questo tipo di esempio dal mio libro:

class RoundFloat(float):
    def __new__(cls, val):
        return float.__new__(cls, round(val, 2))

È considerato immutabile a causa della struttura / gerarchia della classe? Il significato floatè in cima alla classe ed è la sua chiamata al metodo. Simile a questo tipo di esempio (anche se il mio libro dice che dictè mutabile):

class SortedKeyDict(dict):
    def __new__(cls, val):
        return dict.__new__(cls, val.clear())

Considerando che qualcosa di mutabile ha metodi all'interno della classe, con questo tipo di esempio:

class SortedKeyDict_a(dict):
    def example(self):
        return self.keys()

Inoltre, per ultimo class(SortedKeyDict_a), se gli passo questo tipo di set:

d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))

senza chiamare il examplemetodo, restituisce un dizionario. Il SortedKeyDictcon lo __new__contrassegna come un errore. Ho provato a passare numeri interi alla RoundFloatclasse con __new__e non ha segnalato errori.


Puoi anche controllare l' assegnazione dell'elenco con [:] e python quando usare copy.copy a cui ho anche risposto per ulteriori informazioni sulla mutabilità.
AGF

Risposte:


232

Che cosa? I galleggianti sono immutabili? Ma non posso farlo

x = 5.0
x += 7.0
print x # 12.0

Quel "mut" non è x?

Bene, sei d'accordo che le stringhe siano immutabili, giusto? Ma puoi fare la stessa cosa.

s = 'foo'
s += 'bar'
print s # foobar

Il valore della variabile cambia, ma cambia cambiando a cosa si riferisce la variabile. Un tipo mutabile può cambiare in questo modo e può anche cambiare "sul posto".

Ecco la differenza

x = something # immutable type
print x
func(x)
print x # prints the same thing

x = something # mutable type
print x
func(x)
print x # might print something different

x = something # immutable type
y = x
print x
# some statement that operates on y
print x # prints the same thing

x = something # mutable type
y = x
print x
# some statement that operates on y
print x # might print something different

Esempi concreti

x = 'foo'
y = x
print x # foo
y += 'bar'
print x # foo

x = [1, 2, 3]
y = x
print x # [1, 2, 3]
y += [3, 2, 1]
print x # [1, 2, 3, 3, 2, 1]

def func(val):
    val += 'bar'

x = 'foo'
print x # foo
func(x)
print x # foo

def func(val):
    val += [3, 2, 1]

x = [1, 2, 3]
print x # [1, 2, 3]
func(x)
print x # [1, 2, 3, 3, 2, 1]

5
Quello che mi spieghi significa per me: le variabili mutabili vengono passate per riferimento, le variabili immutabili vengono passate per valore. È corretto ?
Lorenz Meyer,

17
Quasi, ma non esattamente. Tecnicamente, tutte le variabili sono passate per riferimento in Python, ma hanno una semantica più simile al passaggio per valore in C. Un controesempio alla tua analogia è se lo fai def f(my_list): my_list = [1, 2, 3]. Con il riferimento pass-by in C, il valore dell'argomento potrebbe cambiare chiamando quella funzione. In Python, quella funzione non fa nulla. def f(my_list): my_list[:] = [1, 2, 3]farebbe qualcosa.
morningstar

6
I tipi mutabili possono essere modificati in atto. I tipi immutabili non possono cambiare sul posto. Questo è il modo in cui Python vede il mondo. Indipendentemente da come le variabili vengono passate alle funzioni.
ychaouche,

13
La differenza chiave tra la semantica di Python e la semantica di riferimento pass-by C ++ è che l'assegnazione non è mutazione in Python, ed è in C ++. (Ma ovviamente ciò è complicato dal fatto che l'assegnazione aumentata, come a a += bvolte è una mutazione. E il fatto che l'assegnazione a una parte di un oggetto più grande a volte significa una mutazione di quell'oggetto più grande, ma mai una mutazione della parte - ad esempio, a[0] = bnon muta a[0], ma probabilmente muta a... Ecco perché potrebbe essere meglio non provare a mettere le cose in termini di C ++ e invece descrivere semplicemente cosa fa Python nei suoi termini ...)
abarnert

2
Ho trovato questa risposta fuorviante perché non usa id (), che è essenziale per capire cosa significa immutabile.
pawel_winzig,

185

Devi capire che Python rappresenta tutti i suoi dati come oggetti. Alcuni di questi oggetti come elenchi e dizionari sono mutabili, il che significa che puoi cambiare il loro contenuto senza cambiare la loro identità. Altri oggetti come numeri interi, float, stringhe e tuple sono oggetti che non possono essere modificati. Un modo semplice per capire è se dai un'occhiata a un ID oggetto.

Sotto vedi una stringa che è immutabile. Non puoi cambiarne il contenuto. Solleverà un TypeErrorse provi a cambiarlo. Inoltre, se assegniamo nuovi contenuti, viene creato un nuovo oggetto anziché i contenuti da modificare.

>>> s = "abc"
>>>id(s)
4702124
>>> s[0] 
'a'
>>> s[0] = "o"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> s = "xyz"
>>>id(s)
4800100
>>> s += "uvw"
>>>id(s)
4800500

Puoi farlo con un elenco e non cambierà l'identità degli oggetti

>>> i = [1,2,3]
>>>id(i)
2146718700
>>> i[0] 
1
>>> i[0] = 7
>>> id(i)
2146718700

Per saperne di più sul modello di dati di Python puoi dare un'occhiata al riferimento di linguaggio Python:


4
+1 Per il collegamento ai documenti Python. Tuttavia mi ci è voluto del tempo prima che mi rendessi conto che oggi è necessario differenziare tra Python 2 e 3: ho aggiornato la risposta per enfatizzarlo.
benjamin,

107

Tipo immutabile comune:

  1. numeri: int(), float(),complex()
  2. sequenze immutabili: str(), tuple(), frozenset(),bytes()

Tipo mutabile comune (quasi tutto il resto):

  1. sequenze mutabili: list(),bytearray()
  2. impostare il tipo: set()
  3. tipo di mappatura: dict()
  4. classi, istanze di classe
  5. eccetera.

Un trucco per verificare rapidamente se un tipo è modificabile o meno è utilizzare la id()funzione integrata.

Esempi, usando su intero,

>>> i = 1
>>> id(i)
***704
>>> i += 1
>>> i
2
>>> id(i)
***736 (different from ***704)

usando sulla lista,

>>> a = [1]
>>> id(a)
***416
>>> a.append(2)
>>> a
[1, 2]
>>> id(a)
***416 (same with the above id)

11
Ben spiegato. Mi è piaciuto il concetto di controllo di id(). +1.
Parag Tyagi,

4
In realtà l'uso di id()è fuorviante qui. Un determinato oggetto avrà sempre lo stesso ID durante il suo ciclo di vita, ma oggetti diversi che esistono in momenti diversi potrebbero avere lo stesso ID a causa della garbage collection.
agosto

37

Innanzitutto, se una classe ha metodi o quale sia la sua struttura di classe non ha nulla a che fare con la mutabilità.

intse floatsono immutabili . Se lo faccio

a = 1
a += 5

Indica il nome ain un punto 1della memoria sulla prima riga. Sulla seconda riga, si alza lo sguardo che 1, aggiunge 5, ottiene 6, quindi i punti ain quella 6in memoria - non ha cambiare la 1ad una 6in alcun modo. La stessa logica si applica ai seguenti esempi, usando altri tipi immutabili :

b = 'some string'
b += 'some other string'
c = ('some', 'tuple')
c += ('some', 'other', 'tuple')

Per i tipi mutabili , posso fare qualcosa che cambia in modo assoluto il valore in cui è memorizzato . Con:

d = [1, 2, 3]

Ho creato una lista delle posizioni di 1, 2e 3in memoria. Se poi lo faccio

e = d

Indico solo egli stessilist d punti in. Posso quindi fare:

e += [4, 5]

E l'elenco che sia ee dpunti a saranno aggiornati per avere anche le posizioni di 4e5 in memoria.

Se torno a un tipo immutabile e lo faccio con un tuple:

f = (1, 2, 3)
g = f
g += (4, 5)

Quindi fpunta ancora solo all'originaletuple : hai indicato gun completamente nuovotuple .

Ora, con il tuo esempio di

class SortedKeyDict(dict):
    def __new__(cls, val):
        return dict.__new__(cls, val.clear())

Dove passi

d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))

(che è un tupledi tuples) come val, stai ricevendo un errore perché tuples non ha un .clear()metodo - dovresti passare dict(d)perché valfunzioni, nel qual caso otterrai uno spazio vuoto SortedKeyDictdi conseguenza.


2
Questa è un'ottima spiegazione. Ho adorato questa domanda e molte (nuove) prospettive interessanti per spiegarlo.
Scienziato fallito

25

Se vieni su Python da un'altra lingua (tranne una che è molto simile a Python, come Ruby), e insisti a capirlo in termini di quell'altra lingua, ecco dove le persone di solito si confondono:

>>> a = 1
>>> a = 2 # I thought int was immutable, but I just changed it?!

In Python, l'assegnazione non è una mutazione in Python.

In C ++, se scrivi a = 2, stai chiamando a.operator=(2), il che cambierà l'oggetto memorizzato a. (E se non vi era alcun oggetto archiviato a, si tratta di un errore.)

In Python, a = 2non fa nulla per ciò che è stato archiviato a; significa solo che 2ora è memorizzato in ainvece. (E se non ci fosse alcun oggetto memorizzato a, va bene.)


In definitiva, questo fa parte di una distinzione ancora più profonda.

Una variabile in un linguaggio come C ++ è una posizione digitata in memoria. Se aè un int, ciò significa che sono 4 byte da qualche parte che il compilatore sa dovrebbe essere interpretato come un int. Quindi, quando lo fai a = 2, cambia ciò che è archiviato in quei 4 byte di memoria da 0, 0, 0, 1a 0, 0, 0, 2. Se c'è un'altra variabile int da qualche altra parte, ha i suoi 4 byte.

Una variabile in un linguaggio come Python è un nome per un oggetto che ha una vita propria. C'è un oggetto per il numero 1e un altro oggetto per il numero 2. E anon sono 4 byte di memoria che sono rappresentati come int, è solo un nome che punta 1all'oggetto. Non ha senso a = 2trasformare il numero 1 nel numero 2 (ciò darebbe a qualsiasi programmatore Python troppa potenza per cambiare il funzionamento fondamentale dell'universo); quello che fa invece è semplicemente adimenticare l' 1oggetto e puntare 2invece sull'oggetto.


Quindi, se l'assegnazione non è una mutazione, che è una mutazione?

  • Chiamare un metodo che è documentato per mutare, come a.append(b). (Si noti che questi metodi restituiscono quasi sempre None). I tipi immutabili non hanno tali metodi, di solito i tipi mutabili.
  • Assegnare a una parte dell'oggetto, come a.spam = bo a[0] = b. I tipi immutabili non consentono l'assegnazione ad attributi o elementi, i tipi mutabili in genere consentono l'uno o l'altro.
  • A volte usando il compito aumentato, come a += b, a volte no. I tipi mutabili di solito mutano il valore; i tipi immutabili non lo fanno mai e ti danno invece una copia (calcolano a + b, quindi assegnano il risultato a a).

Ma se l'assegnazione non è una mutazione, come sta assegnando una parte della mutazione dell'oggetto? Ecco dove diventa difficile. a[0] = bfa non mutate a[0](ancora una volta, a differenza di C ++), ma fa mutarea (a differenza di C ++, se non indirettamente).

Tutto questo è il motivo per cui probabilmente è meglio non provare a mettere la semantica di Python in termini di una lingua a cui sei abituato, e invece imparare la semantica di Python alle loro condizioni.


2
Dì a = 'ciao'. a [0] = 'f' avrà 'print a' print out 'fi' (Sono giusto fino ad ora?), quindi quando dici che non muta uno [0], piuttosto un, cosa significa ? Anche una [n] ha il suo posto adesso, e cambiando il suo valore lo indica un valore diverso?
Daniel Springer,

19

Se un oggetto è mutabile o meno dipende dal suo tipo. Questo non dipende dal fatto che abbia o meno determinati metodi, né dalla struttura della gerarchia di classi.

I tipi definiti dall'utente (cioè le classi) sono generalmente mutabili. Vi sono alcune eccezioni, come semplici sottoclassi di tipo immutabile. Altri tipi immutabili includono alcuni tipi built-in, come int, float, tupleestr , così come alcune classi Python implementate in C.

Una spiegazione generale dal capitolo "Modello di dati" nella Guida di riferimento di Python " :

Il valore di alcuni oggetti può cambiare. Si dice che gli oggetti il ​​cui valore può cambiare siano mutabili; gli oggetti il ​​cui valore è immutabile una volta creati vengono chiamati immutabili.

(Il valore di un oggetto contenitore immutabile che contiene un riferimento a un oggetto mutabile può cambiare quando viene modificato il valore di quest'ultimo; tuttavia il contenitore è ancora considerato immutabile, poiché la raccolta di oggetti che contiene non può essere modificata. Pertanto, l'immutabilità non è rigorosamente lo stesso che avere un valore immutabile, è più sottile.)

La mutabilità di un oggetto è determinata dal suo tipo; per esempio, numeri, stringhe e tuple sono immutabili, mentre dizionari ed elenchi sono mutabili.


+1 Nota però che solo alcuni tipi di estensione (potresti voler rivedere la tua definizione di ciò, tutti i tipi predefiniti di Python sono implementati in C) sono immutabili. Altri (la maggior parte, oserei dire) sono perfettamente mutabili.

@delnan Come si chiama "tipi di estensioni" ?
eyquem,

@eyquem: ho usato il termine "tipi di estensione" in modo errato nella mia risposta e delnan si riferiva a quello. Dopo il suo commento ho rivisto la mia risposta ed evitato di usare questo termine.
taleinat

19

Differenza tra oggetti mutabili e immutabili

definizioni

Oggetto mutabile : oggetto che può essere modificato dopo averlo creato.
Oggetto immutabile : oggetto che non può essere modificato dopo averlo creato.

In Python se si modifica il valore dell'oggetto immutabile, verrà creato un nuovo oggetto.

Oggetti mutabili

Ecco gli oggetti in Python di tipo mutevole:

  1. list
  2. Dictionary
  3. Set
  4. bytearray
  5. user defined classes

Oggetti immutabili

Ecco gli oggetti in Python di tipo immutabile:

  1. int
  2. float
  3. decimal
  4. complex
  5. bool
  6. string
  7. tuple
  8. range
  9. frozenset
  10. bytes

Alcune domande senza risposta

Domande : la stringa è un tipo immutabile?
Risposta : , ma puoi spiegarlo: Prova 1 :

a = "Hello"
a +=" World"
print a

Produzione

"Hello World"

Nell'esempio sopra la stringa è stata creata una volta come "Hello", quindi modificata in "Hello World". Ciò implica che la stringa è di tipo mutabile. Ma non è quando controlliamo la sua identità per vedere se è di tipo mutevole o no.

a = "Hello"
identity_a = id(a)
a += " World"
new_identity_a = id(a)
if identity_a != new_identity_a:
    print "String is Immutable"

Produzione

String is Immutable

Prova 2 :

a = "Hello World"
a[0] = "M"

Produzione

TypeError 'str' object does not support item assignment

Domande : Tuple è un tipo immutabile?
Risposta : , lo è. Prova 1 :

tuple_a = (1,)
tuple_a[0] = (2,)
print a

Produzione

'tuple' object does not support item assignment

In [46]: a = "Hello" In [47]: id (a) Out [47]: 140071263880128 In [48]: a = a.replace ("H", "g") In [49]: a Out [49]: 'gello' In [50]: id (a) Out [50]: 140071263881040
Argus Malware,

ti andrebbe di provare il problema di assegnazione degli articoli al mio esempio di cui sopra
Argus Malware,

l'assegnazione degli articoli non viene emessa in tipi immutabili. Nel tuo caso stai cambiando la stringa a ma in memoria la sua assegnazione a una nuova variabile. L'assegnazione degli oggetti nel mio caso non cambierà la memoria della variabile come nel caso dell'elenco o del dizionario. se stai sostituendo stai creando una nuova variabile che non modifica la variabile esistente
anand tripathi

@ArgusMalware nel tuo caso, due ID sono uguali a causa del primo riciclato da GC, quindi il secondo riutilizza la memoria.
Cologler,

11

Un oggetto mutabile deve avere almeno un metodo in grado di mutare l'oggetto. Ad esempio, l' listoggetto ha il appendmetodo, che in realtà cambierà l'oggetto:

>>> a = [1,2,3]
>>> a.append('hello') # `a` has mutated but is still the same object
>>> a
[1, 2, 3, 'hello']

ma la classe floatnon ha alcun metodo per mutare un oggetto float. Tu puoi fare:

>>> b = 5.0 
>>> b = b + 0.1
>>> b
5.1

ma l' =operando non è un metodo. Crea un legame tra la variabile e qualunque cosa sia alla sua destra, nient'altro. Non cambia mai né crea oggetti. È una dichiarazione di ciò che la variabile indicherà, da ora in poi.

Quando si esegue b = b + 0.1l' =operando, la variabile viene associata a un nuovo float, che viene creato con il risultato di 5 + 0.1.

Quando si assegna una variabile a un oggetto esistente, mutabile o no, l' =operando associa la variabile a quell'oggetto. E non succede altro

In entrambi i casi, i =giusti vincoli. Non cambia né crea oggetti.

Quando lo fai a = 1.0, l' =operando non è quello che crea il float, ma la 1.0parte della linea. In realtà quando scrivi 1.0è una scorciatoia per float(1.0)una chiamata del costruttore che restituisce un oggetto float. (Questo è il motivo per cui se si digita 1.0e si preme invio si ottiene la "eco" 1.0stampata di seguito; questo è il valore di ritorno della funzione di costruzione chiamata)

Ora, se bè un float e si assegna a = b, entrambe le variabili puntano allo stesso oggetto, ma in realtà le variabili non possono comunicare tra loro, perché l'oggetto è immutabile, e se lo fai b += 1, ora bpunta a un nuovo oggetto, ed aè ancora indicando il vecchio e non posso sapere cosa bsta indicando.

ma se cè, diciamo, a list, e tu lo assegni a = c, ora ae cpuoi "comunicare", perché listè mutevole, e se lo fai c.append('msg'), allora solo controllando aricevi il messaggio.

(A proposito, ogni oggetto ha un numero ID univoco associato, a cui puoi arrivare id(x). Quindi puoi verificare se un oggetto è lo stesso o non verificare se il suo ID univoco è cambiato.)


6

Una classe è immutabile se ogni oggetto di quella classe ha un valore fisso all'istanza che non può essere SOSTENUTAMENTE modificato

In altre parole, modificare l'intero valore di quella variabile (name)o lasciarlo da solo.

Esempio:

my_string = "Hello world" 
my_string[0] = "h"
print my_string 

ti aspettavi che funzionasse e stampasse ciao mondo, ma questo genererà il seguente errore:

Traceback (most recent call last):
File "test.py", line 4, in <module>
my_string[0] = "h"
TypeError: 'str' object does not support item assignment

L'interprete sta dicendo: non posso cambiare il primo carattere di questa stringa

dovrai cambiare il tutto stringper farlo funzionare:

my_string = "Hello World" 
my_string = "hello world"
print my_string #hello world

controlla questa tabella:

inserisci qui la descrizione dell'immagine

fonte


Come si possono modificare i componenti di una stringa Python in un modo più conciso di quanto mostrato sopra?
Luke Davis,

@LukeDavis Potresti farlo my_string = 'h' + my_string[1:]. Questo genererà una nuova stringa chiamata my_string, e l'originale my_string è sparito (stampa id(my_string)per vedere questo). Ovviamente non è molto flessibile, per il caso più generale è possibile convertire in elenco e l = list(my_string) l[0] = 'h' my_string = ''.join(l)
viceversa

5

Mi sembra che stai combattendo con la domanda su cosa significhi realmente mutevole / immutabile . Quindi, ecco una semplice spiegazione:

Per prima cosa abbiamo bisogno di una base su cui basare l'esplosione.

Quindi pensa a tutto ciò che programmi come un oggetto virtuale, qualcosa che viene salvato nella memoria di un computer come una sequenza di numeri binari. (Non tentare di immaginarlo troppo, però. ^^) Ora nella maggior parte dei linguaggi per computer non lavorerai direttamente con questi numeri binari, ma piuttosto utilizzerai un'interpretazione dei numeri binari.

Ad esempio, non pensi a numeri come 0x110, 0xaf0278297319 o simili, ma invece pensi a numeri come 6 o Stringhe come "Ciao, mondo". Mai meno numeri di tesi o stringhe sono un'interpretazione di un numero binario nella memoria del computer. Lo stesso vale per qualsiasi valore di una variabile.

In breve: Noi non programmiamo con valori effettivi, ma con interpretazioni di valori binari attuali.

Ora abbiamo interpretazioni che non devono essere cambiate per motivi di logica e altre "cose ​​ordinate" mentre ci sono interpretazioni che potrebbero essere cambiate. Ad esempio, pensa alla simulazione di una città, in altre parole un programma in cui ci sono molti oggetti virtuali e alcuni di questi sono case. Ora questi oggetti virtuali (le case) possono essere cambiati e possono ancora essere considerati le stesse case? Beh, certo che possono. Quindi sono mutabili: possono essere cambiati senza diventare un oggetto "completamente" diverso.

Ora pensiamo agli interi: anche questi sono oggetti virtuali (sequenze di numeri binari nella memoria di un computer). Quindi, se ne cambiamo uno, come aumentare il valore di sei per uno, è ancora un sei? Beh, certo che no. Quindi qualsiasi numero intero è immutabile.

Quindi: se qualsiasi cambiamento in un oggetto virtuale significa che in realtà diventa un altro oggetto virtuale, allora si chiama immutabile.

Osservazioni finali:

(1) Non confondere mai la tua esperienza nel mondo reale di mutevole e immutabile con la programmazione in un determinato linguaggio:

Ogni linguaggio di programmazione ha una propria definizione su quali oggetti possono essere disattivati ​​e quali no.

Quindi, mentre ora puoi capire la differenza di significato, devi ancora imparare l'implementazione effettiva per ciascun linguaggio di programmazione. ... In effetti potrebbe esserci uno scopo di un linguaggio in cui un 6 potrebbe essere disattivato per diventare un 7. Quindi, questo sarebbe un po 'roba folle o interessante, come simulazioni di universi paralleli.

(2) Questa spiegazione non è certamente scientifica, ha lo scopo di aiutarti a capire la differenza tra mutevole e immutabile.


5

L'obiettivo di questa risposta è quello di creare un unico posto per trovare tutte le buone idee su come dire se hai a che fare con mutazioni / non mutanti (immutabili / mutabili) e, dove possibile, cosa fare al riguardo? Ci sono momenti in cui la mutazione è indesiderabile e il comportamento di Python in questo senso può sembrare contro-intuitivo per i programmatori che arrivano da altre lingue.

Secondo un utile post di @ mina-gabriel:

Analizzando quanto sopra e combinando w / a post di @ arrakëën:

Cosa non può cambiare inaspettatamente?

  • gli scalari (tipi di variabili che memorizzano un singolo valore) non cambiano in modo imprevisto
    • esempi numerici: int (), float (), complex ()
  • ci sono alcune "sequenze mutabili":
    • str (), tuple (), frozenset (), bytes ()

Che cosa può?

  • elenca come oggetti (elenchi, dizionari, set, bytearray ())
  • un post qui dice anche classi e istanze di classe, ma ciò può dipendere da ciò che la classe eredita e / o da come è stata costruita.

per "inaspettatamente" intendo che programmatori di altre lingue potrebbero non aspettarsi questo comportamento (con l'eccezione di Ruby, e forse qualche altro linguaggio "simile a Python").

Aggiungendo a questa discussione:

Questo comportamento è un vantaggio quando ti impedisce di popolare accidentalmente il tuo codice con copie multiple di grandi strutture di dati che consumano memoria. Ma quando questo è indesiderabile, come possiamo aggirarlo?

Con le liste, la soluzione semplice è costruirne una nuova in questo modo:

list2 = list (list1)

con altre strutture ... la soluzione può essere più complicata. Un modo è quello di passare in rassegna gli elementi e aggiungerli a una nuova struttura di dati vuota (dello stesso tipo).

le funzioni possono mutare l'originale quando si passa in strutture mutabili. Come dire?

  • Ci sono alcuni test forniti su altri commenti su questo thread, ma poi ci sono commenti che indicano che questi test non sono una prova completa
  • object.function () è un metodo dell'oggetto originale ma solo alcuni di questi mutano. Se non restituiscono nulla, probabilmente lo fanno. Ci si aspetterebbe che .append () muti senza testarlo dato il suo nome. .union () restituisce l'unione di set1.union (set2) e non muta. In caso di dubbio, la funzione può essere controllata per un valore di ritorno. Se return = None, non muta.
  • sort () potrebbe essere una soluzione alternativa in alcuni casi. Poiché restituisce una versione ordinata dell'originale, può consentire di archiviare una copia non mutata prima di iniziare a lavorare sull'originale in altri modi. Tuttavia, questa opzione presuppone che non ti interessi l'ordine degli elementi originali (se lo fai, devi trovare un altro modo). Al contrario .sort () muta l'originale (come ci si potrebbe aspettare).

Approcci non standard (nel caso utile): trovato su github pubblicato sotto una licenza MIT:

  • repository github sotto: tobgu chiamato: pyrsistent
  • Che cos'è: codice della struttura dati persistente di Python scritto per essere utilizzato al posto delle strutture dati principali quando la mutazione è indesiderabile

Per le classi personalizzate, @semicolon suggerisce di verificare se esiste una __hash__funzione perché gli oggetti mutabili generalmente non dovrebbero avere una __hash__()funzione.

Questo è tutto ciò che ho accumulato su questo argomento per ora. Altre idee, correzioni, ecc. Sono benvenute. Grazie.


3

Un modo di pensare alla differenza:

Le assegnazioni a oggetti immutabili in Python possono essere pensate come copie profonde, mentre le assegnazioni a oggetti mutabili sono poco profonde


1
Questo non è corretto Tutti i compiti in Python sono per riferimento. Non è prevista alcuna copia.
agosto

3

La risposta più semplice:

Una variabile mutabile è una variabile il cui valore può cambiare in atto, mentre in una variabile immutabile il cambiamento di valore non avverrà in atto. La modifica di una variabile immutabile ricostruirà la stessa variabile.

Esempio:

>>>x = 5

Creerà un valore 5 a cui fa riferimento x

x -> 5

>>>y = x

Questa affermazione farà riferimento a 5 di x

x -------------> 5 <----------- y

>>>x = x + y

Poiché x essendo un numero intero (tipo immutabile) è stato ricostruito.

Nell'istruzione, l'espressione su RHS risulterà nel valore 10 e quando questo viene assegnato a LHS (x), x verrà ricostruito in 10. Quindi ora

x ---------> 10

y ---------> 5


-1

Non ho letto tutte le risposte, ma la risposta selezionata non è corretta e penso che l'autore abbia l'idea che essere in grado di riassegnare una variabile significa che qualunque tipo di dati sia mutabile. Questo non è il caso. La mutabilità ha a che fare con il passaggio per riferimento anziché con il passaggio per valore.

Diciamo che hai creato un elenco

a = [1,2]

Se dovessi dire:

b = a
b[1] = 3

Anche se hai riassegnato un valore su B, riassegnerà anche il valore su a. È perché quando si assegna "b = a". Stai passando il "Riferimento" all'oggetto piuttosto che una copia del valore. Questo non è il caso di stringhe, float, ecc. Ciò rende mutevole l'elenco, i dizionari e cose simili, ma booleani, float ecc.


-1

Per oggetti immutabili, l'assegnazione crea una nuova copia di valori, ad esempio.

x=7
y=x
print(x,y)
x=10 # so for immutable objects this creates a new copy so that it doesnot 
#effect the value of y
print(x,y)

Per oggetti mutabili, l'assegnazione non crea un'altra copia di valori. Per esempio,

x=[1,2,3,4]
print(x)
y=x #for immutable objects assignment doesn't create new copy 
x[2]=5
print(x,y) # both x&y holds the same list

1
Assolutamente scorretto L'assegnazione non crea mai una copia . Si prega di leggere nedbatchelder.com/text/names.html Nel primo caso, x=10è semplicemente un altro compito , mentre x[2] = 5chiama un metodo mutatore. intgli oggetti mancano semplicemente di metodi mutatori , ma la semantica dell'assegnazione dei pitoni non dipende dal tipo
juanpa.arrivillaga,

-2

In Python c'è un modo semplice per sapere:

Immutabile:

    >>> s='asd'
    >>> s is 'asd'
    True
    >>> s=None
    >>> s is None
    True
    >>> s=123
    >>> s is 123
    True

Mutevole:

>>> s={}
>>> s is {}
False
>>> {} is {}
Flase
>>> s=[1,2]
>>> s is [1,2]
False
>>> s=(1,2)
>>> s is (1,2)
False

E:

>>> s=abs
>>> s is abs
True

Quindi penso che la funzione integrata sia immutabile in Python.

Ma davvero non capisco come funziona float:

>>> s=12.3
>>> s is 12.3
False
>>> 12.3 is 12.3
True
>>> s == 12.3
True
>>> id(12.3)
140241478380112
>>> id(s)
140241478380256
>>> s=12.3
>>> id(s)
140241478380112
>>> id(12.3)
140241478380256
>>> id(12.3)
140241478380256

È così strano.


Ma questo chiaramente non è valido. Perché le tuple sono immutabili. Digita x = (1, 2)e poi prova e muta x, non è possibile. Un modo che ho trovato per verificare la mutabilità è hashche funziona almeno per gli oggetti incorporati. hash(1) hash('a') hash((1, 2)) hash(True)tutto funziona e hash([]) hash({}) hash({1, 2})tutto non funziona.
punto

@semicolon Per le classi definite dall'utente funzionerà quindi hash()se l'oggetto definisce un __hash__()metodo, anche se le classi definite dall'utente sono generalmente mutabili.
agosto

1
@augurar intendo sì, ma nulla in Python garantirà nulla, perché Python non ha una vera tipizzazione statica o garanzie formali. Ma il hashmetodo è ancora piuttosto buono, perché gli oggetti mutabili non dovrebbero generalmente avere un __hash__()metodo, dal momento che renderli chiavi in ​​un dizionario è semplicemente pericoloso.
punto

1
@augurar e punto e virgola (o altri se lo conoscono): soluzione __hash __ () ... il creatore di una classe personalizzata deve aggiungerla perché sia ​​presente? Se è così, allora la regola è se esiste l'oggetto dovrebbe essere immutabile; se non esiste, non possiamo dirlo dal momento che il creatore potrebbe aver semplicemente lasciato se spento.
TMWP
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.