Le stringhe Python non sono immutabili? Allora perché a + "" + b funziona?


109

La mia comprensione era che le stringhe Python sono immutabili.

Ho provato il seguente codice:

a = "Dog"
b = "eats"
c = "treats"

print a, b, c
# Dog eats treats

print a + " " + b + " " + c
# Dog eats treats

print a
# Dog

a = a + " " + b + " " + c
print a
# Dog eats treats
# !!!

Python non avrebbe dovuto impedire l'assegnazione? Probabilmente mi sto perdendo qualcosa.

Qualche idea?


55
La stringa stessa è immutabile ma l'etichetta può cambiare.
mitch

6
Assegnare un nuovo valore a una variabile esistente è perfettamente valido. Python non ha costanti. Ciò è indipendente dalla mutabilità del tipo di dati.
Felix Kling

14
Potresti voler dare un'occhiata alla id()funzione. aavrà un ID diverso prima e dopo l'assegnazione, indicando che punta a oggetti diversi. Allo stesso modo con codice come b = alo troverai ae bavrà lo stesso ID, indicando che fanno riferimento allo stesso oggetto.
DRH


Il collegamento da delnan è esattamente quello a cui mi riferivo.
mitch

Risposte:


180

In primo luogo ha aindicato la stringa "Dog". Quindi hai modificato la variabile ain modo che punti a una nuova stringa "Il cane mangia dei bocconcini". Non hai effettivamente modificato la stringa "Dog". Le stringhe sono immutabili, le variabili possono puntare a quello che vogliono.


34
È ancora più convincente provare qualcosa come x = 'abc'; x [1] = 'x' nella
sostituzione di

1
Se desideri capire un po 'di più gli interni, vedi la mia risposta. stackoverflow.com/a/40702094/117471
Bruno Bronosky

53

Gli oggetti stringa stessi sono immutabili.

La variabile, ache punta alla stringa, è modificabile.

Tener conto di:

a = "Foo"
# a now points to "Foo"
b = a
# b points to the same "Foo" that a points to
a = a + a
# a points to the new string "FooFoo", but b still points to the old "Foo"

print a
print b
# Outputs:

# FooFoo
# Foo

# Observe that b hasn't changed, even though a has.

@jason prova lo stesso tipo di operazioni con le liste (che sono modificabili) per vedere la differenza a.append (3) corrisponde a a = a + "Foo"
jimifiki

1
@jimifiki a.append(3) non è la stessa cosa di a = a + 3. Non è nemmeno a += 3(l'aggiunta al posto è equivalente a .extend, non a .append).

@delnan e così, cosa? Per mostrare che le stringhe e le liste si comportano diversamente, puoi presumere che a = a + "Foo" sia lo stesso di a.append (qualcosa). In ogni caso non è la stessa cosa. Ovviamente. Eri più felice di leggere a.extend ([qualcosa]) invece di a.append (qualcosa)? Non vedo una grande differenza in questo contesto. Ma probabilmente mi sto perdendo qualcosa. La verità dipende dal contesto
jimifiki

@jimifiki: di cosa stai parlando? +si comporta allo stesso modo per elenchi e stringhe: si concatena creando una nuova copia e non mutando nessuno dei due operandi.

6
Il punto veramente importante da togliere a tutto questo è che le stringhe non hanno una append funzione perché sono immutabili.
Lily Chung

46

La variabile a punta all'oggetto "Dog". È meglio pensare alla variabile in Python come a un tag. Puoi spostare il tag su oggetti diversi, come hai fatto quando sei passato a = "dog"a a = "dog eats treats".

Tuttavia, l'immutabilità si riferisce all'oggetto, non al tag.


Se provassi a[1] = 'z'a "dog"entrare "dzg", otterrai l'errore:

TypeError: 'str' object does not support item assignment" 

perché le stringhe non supportano l'assegnazione di elementi, quindi sono immutabili.


19

Qualcosa è mutabile solo quando siamo in grado di cambiare i valori contenuti nella posizione di memoria senza cambiare la posizione di memoria stessa.

Il trucco è: se trovi che la posizione di memoria prima e dopo la modifica sono le stesse, è modificabile.

Ad esempio, l'elenco è modificabile. Come?

>> a = ['hello']
>> id(a)
139767295067632

# Now let's modify
#1
>> a[0] = "hello new"
>> a
['hello new']
Now that we have changed "a", let's see the location of a
>> id(a)
139767295067632
so it is the same as before. So we mutated a. So list is mutable.

Una stringa è immutabile. Come lo proviamo?

> a = "hello"
> a[0]
'h'
# Now let's modify it
> a[0] = 'n'
----------------------------------------------------------------------

noi abbiamo

TypeError: l'oggetto 'str' non supporta l'assegnazione di elementi

Quindi non abbiamo modificato la stringa. Significa che una stringa è immutabile.

Durante la riassegnazione, si modifica la variabile in modo che punti a una nuova posizione stessa. Qui non hai mutato la stringa, ma mutato la variabile stessa. Quanto segue è quello che stai facendo.

>> a = "hello"
>> id(a)
139767308749440
>> a ="world"
>> id(a)
139767293625808

idprima e dopo la riassegnazione è diverso, quindi questo dimostra che in realtà non stai mutando, ma stai puntando la variabile in una nuova posizione. Che non sta mutando quella stringa, ma mutando quella variabile.


11

Una variabile è solo un'etichetta che punta a un oggetto. L'oggetto è immutabile, ma puoi fare in modo che l'etichetta punti a un oggetto completamente diverso se lo desideri.


8

Tener conto di:

>>> a='asdf'
>>> a.__repr__
<method-wrapper '__repr__' of str object at 0x1091aab90>
>>> a='asdf'
>>> a.__repr__
<method-wrapper '__repr__' of str object at 0x1091aab90>
>>> a='qwer'
>>> a.__repr__
<method-wrapper '__repr__' of str object at 0x109198490>

Si noti che la posizione della memoria esadecimale non è cambiata quando ho memorizzato lo stesso valore nella variabile due volte. È cambiato quando ho memorizzato un valore diverso. La stringa è immutabile. Non per fanatismo, ma perché si paga la penalità sulle prestazioni di creare un nuovo oggetto in memoria. La variabile aè solo un'etichetta che punta a quell'indirizzo di memoria. Può essere modificato per indicare qualsiasi cosa.


7

L'istruzione a = a + " " + b + " " + cpuò essere suddivisa in base ai puntatori.

a + " "dice dammi a cosa apunta, che non può essere modificato, e aggiungi " "al mio set di lavoro corrente.

memoria:

working_set = "Dog "
a = "Dog" 
b = "eats"
c = "treats"

+ bdice dammi a cosa bpunta, che non può essere modificato, e aggiungilo al working set corrente.

memoria:

working_set = "Dog eats"
a = "Dog" 
b = "eats"
c = "treats"

+ " " + cdice aggiungi " "al set corrente. Quindi dammi quali cpunti, che non possono essere modificati, e aggiungili al working set corrente. memoria:

working_set = "Dog eats treats"
a = "Dog" 
b = "eats"
c = "treats"

Infine, a =dice imposta il mio puntatore in modo che punti al set risultante.

memoria:

a = "Dog eats treats"
b = "eats"
c = "treats"

"Dog"viene recuperato, perché nessun altro puntatore si connette al suo pezzo di memoria. Non abbiamo mai modificato la sezione della memoria "Dog"in cui risiedeva, che è ciò che si intende per immutabile. Tuttavia, possiamo cambiare le eventuali etichette che puntano a quella sezione di memoria.


6
l = [1,2,3]
print id(l)
l.append(4)
print id(l) #object l is the same

a = "dog"
print id(a)
a = "cat"
print id(a) #object a is a new object, previous one is deleted

5

C'è una differenza tra i dati e l'etichetta a cui sono associati. Ad esempio quando lo fai

a = "dog"

i dati "dog"vengono creati e messi sotto l'etichetta a. L'etichetta può cambiare ma ciò che è nella memoria no. I dati "dog"esisteranno ancora in memoria (fino a quando il Garbage Collector non li elimina) dopo averlo fatto

a = "cat"

Nel tuo programma aora ^ punta a ^ "cat"ma la stringa "dog"non è cambiata.


3

Le stringhe Python sono immutabili. Tuttavia, anon è una stringa: è una variabile con un valore stringa. Non puoi modificare la stringa, ma puoi cambiare il valore della variabile in una nuova stringa.


2

Le variabili possono puntare a dove vogliono .. Verrà generato un errore se esegui le seguenti operazioni:

a = "dog"
print a                   #dog
a[1] = "g"                #ERROR!!!!!! STRINGS ARE IMMUTABLE

2

Gli oggetti stringa Python non sono modificabili. Esempio:

>>> a = 'tanim'
>>> 'Address of a is:{}'.format(id(a))
'Address of a is:64281536'
>>> a = 'ahmed'
>>> 'Address of a is:{}'.format(id(a))
'Address of a is:64281600'

In questo esempio possiamo vedere che quando assegniamo un valore diverso in a non cambia, viene creato un nuovo oggetto.
E non può essere modificato. Esempio:

  >>> a[0] = 'c'
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    **TypeError**: 'str' object does not support item assignment

Si verifica un errore.


2

"mutabile" significa che possiamo cambiare il contenuto della stringa, "immutabile" significa che non possiamo aggiungere una stringa in più.

fare clic per la prova fotografica


1

>>> a = 'dogs'

>>> a.replace('dogs', 'dogs eat treats')

'dogs eat treats'

>>> print a

'dogs'

Immutabile, non è vero ?!

La parte del cambio variabile è già stata discussa.


1
Questo non sta provando o confutando la mutabilità delle stringhe Python, solo che il replace()metodo restituisce una nuova stringa.
Brent Hronik

1

Considera questa aggiunta al tuo esempio

 a = "Dog"
 b = "eats"
 c = "treats"
 print (a,b,c)
 #Dog eats treats
 d = a + " " + b + " " + c
 print (a)
 #Dog
 print (d)
 #Dog eats treats

Una delle spiegazioni più precise che ho trovato in un blog è:

In Python, (quasi) tutto è un oggetto. Quelle che comunemente chiamiamo "variabili" in Python sono chiamate più propriamente nomi. Allo stesso modo, "assegnazione" è in realtà l'associazione di un nome a un oggetto. Ogni associazione ha un ambito che ne definisce la visibilità, solitamente il blocco in cui ha origine il nome.

Per esempio:

some_guy = 'Fred'
# ...
some_guy = 'George'

Quando in seguito diciamo some_guy = 'George', l'oggetto stringa contenente 'Fred' non viene influenzato. Abbiamo appena cambiato l'associazione del nome some_guy. Tuttavia, non abbiamo modificato gli oggetti stringa "Fred" o "George". Per quanto ci riguarda, potrebbero vivere indefinitamente.

Collegamento al blog: https://jeffknupp.com/blog/2012/11/13/is-python-callbyvalue-or-callbyreference-neither/


1

Aggiungendo un po 'di più alle risposte sopra menzionate.

id di una variabile cambia in caso di riassegnazione.

>>> a = 'initial_string'
>>> id(a)
139982120425648
>>> a = 'new_string'
>>> id(a)
139982120425776

Ciò significa che abbiamo modificato la variabile ain modo che punti a una nuova stringa. Ora esistono due string oggetti (str):

'initial_string'con id= 139982120425648

e

'new_string'con id= 139982120425776

Considera il codice seguente:

>>> b = 'intitial_string'
>>> id(b)
139982120425648

Ora, bpunta a 'initial_string'e ha lo stesso iddi aprima della riassegnazione.

Pertanto, il 'intial_string'non è stato mutato.


0

riassumendo:

a = 3
b = a
a = 3+2
print b
# 5

Non immutabile:

a = 'OOP'
b = a
a = 'p'+a
print b
# OOP

Immutabile:

a = [1,2,3]
b = range(len(a))
for i in range(len(a)):
    b[i] = a[i]+1

Questo è un errore in Python 3 perché è immutabile. E non è un errore in Python 2 perché chiaramente non è immutabile.


0

La funzione incorporata id()restituisce l'identità di un oggetto come numero intero. Questo numero intero corrisponde solitamente alla posizione dell'oggetto in memoria.

\>>a='dog'
\>>print(id(a))

139831803293008

\>>a=a+'cat'
\>>print(id(a))

139831803293120

Inizialmente, "a" è memorizzato nella posizione di memoria 139831803293008, poiché l'oggetto stringa è immutabile in Python se si tenta di modificare e riassegnare il riferimento verrà rimosso e sarà un puntatore a una nuova posizione di memoria (139831803293120).


0
a = 'dog'
address = id(a)
print(id(a))

a = a + 'cat'
print(id(a))      #Address changes

import ctypes
ctypes.cast(address, ctypes.py_object).value    #value at old address is intact

2
Sebbene questo codice possa risolvere il problema dell'OP, è meglio includere una spiegazione su come il tuo codice risolve il problema dell'OP. In questo modo, i futuri visitatori possono imparare dal tuo post e applicarlo al proprio codice. SO non è un servizio di codifica, ma una risorsa per la conoscenza. Inoltre, è più probabile che le risposte complete e di alta qualità vengano votate. Queste caratteristiche, insieme al requisito che tutti i post siano autonomi, sono alcuni dei punti di forza di SO come piattaforma, che lo differenzia dai forum. Puoi modificare per aggiungere ulteriori informazioni e / o per integrare le tue spiegazioni con la documentazione di origine
SherylHohman

-1

Questa immagine dà la risposta. Per favore leggilo.

inserisci qui la descrizione dell'immagine


-1

Stiamo solo concatenando i due valori di stringa. Non cambiamo mai il valore di (a). Proprio ora (a) rappresentano un altro blocco di memoria che ha valore "dogdog". Perché nel back-end, una variabile non rappresenta mai due blocchi di memoria contemporaneamente. Il valore di (a) prima della concatenazione era "cane". Ma dopo che (a) rappresenta il "cane", perché ora (a) nel rappresentante di backend. il blocco che ha il valore "dogdog". E "cane" è rappresentante. by (b) e "dog" non viene conteggiato come valore di spazzatura fino a quando (b) non rappresenta il "cane".

La confusione è che rappresentiamo i blocchi di memoria (che contengono dati o informazioni) nel backend con lo stesso nome di variabile.


-2

Puoi rendere immutabile un array numpy e utilizzare il primo elemento:

numpyarrayname[0] = "write once"

poi:

numpyarrayname.setflags(write=False)

o

numpyarrayname.flags.writeable = False
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.