2012-02-01 10 views
62

Según entendí, las cadenas de Python son inmutables.¿Las cadenas de Python no son inmutables? Entonces, ¿por qué funciona un + "" + b?

He probado el siguiente código:

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 
# !!! 

No debería haber evitado Python la asignación? Probablemente me esté perdiendo algo.

¿Alguna idea?

+34

La cadena en sí es inmutable, pero la etiqueta puede cambiar. – mitch

+4

La asignación de un nuevo valor a una variable existente es perfectamente válida. Python no tiene constantes. Esto es independiente de la mutabilidad del tipo de datos. –

+5

Es posible que desee echar un vistazo a la función 'id()'. 'a' tendrá una identificación diferente antes y después de la asignación, lo que indica que apunta a diferentes objetos. Del mismo modo, con un código como 'b = a', encontrarás que 'a' y 'b' tendrán la misma identificación, lo que indica que están haciendo referencia al mismo objeto. – DRH

Respuesta

118

Primero a apuntado a la cadena "Perro". Luego cambiaste la variable a para apuntar a una nueva cadena "Dog come golosinas". En realidad no has mutado la cadena "Perro". Las cadenas son inmutables, las variables pueden señalar lo que quieran.

+12

Es aún más convincente intentar algo como x = 'abc'; x [1] = 'x' en la réplica de Python – xpmatteo

+0

Si desea conocer un poco más las funciones internas, consulte mi respuesta. https://stackoverflow.com/a/40702094/117471 –

38

Los objetos de cuerda son inmutables.

La variable, a, que apunta a la cadena, es mutable.

considerar:

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. 
+0

@jason pruebe el mismo tipo de operaciones con listas (que son mutables) para ver la diferencia a.append (3) corresponde a a = a + "Foo" – jimifiki

+1

@jimifiki 'a.append (3)' ** no es ** lo mismo que 'a = a + 3'. Ni siquiera es 'a + = 3' (la suma en el lugar es equivalente a' .extend', no a '.append'). – delnan

+0

@delnan y entonces, ¿qué? Para mostrar que las cadenas y las listas se comportan de manera diferente, puede suponer que a = a + "Foo" es lo mismo que a.append (algo). En cualquier caso, no es lo mismo. Obviamente. ¿Estabas más feliz leyendo a.extend ([algo]) en lugar de a.append (algo)? No veo esa gran diferencia en este contexto. Pero probablemente me estoy perdiendo algo. La verdad depende del contexto – jimifiki

11

Una variable es sólo una etiqueta que apunta a un objeto. El objeto es inmutable, pero puede hacer que la etiqueta apunte a un objeto completamente diferente si lo desea.

3

Las cadenas de Python son inmutables. Sin embargo, a no es una cadena: es una variable con un valor de cadena. No puede mutar la cadena, pero puede cambiar el valor de la variable a una nueva cadena.

5

Hay una diferencia entre los datos y la etiqueta a la que está asociada. Por ejemplo cuando se hace

a = "dog" 

los datos "dog" se crean y se ponen bajo la etiqueta a. La etiqueta puede cambiar, pero lo que está en la memoria no lo hará. Los datos "dog" seguirán existiendo en la memoria (hasta que el recolector de basura lo elimina) después de hacer

a = "cat" 

En su Programm a ahora^^ puntos a "cat" pero la cadena "dog" no ha cambiado.

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

La declaración a = a + " " + b + " " + c se puede desglosar según punteros.

a + " " dice dame lo que a señala, que no se puede cambiar, y agrega " " a mi conjunto de trabajo actual.

memoria:

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

+ b dice dame lo b apunta a que no se pueden cambiar, y agregarlo a la corriente del conjunto de trabajo.

memoria:

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

+ " " + c dice añadir " " al conjunto actual.Luego, dame lo que apunta a c, que no se puede cambiar, y agrégalo al conjunto de trabajo actual. memoria:

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

Por último, a = dice mi establece puntero para señalar que el conjunto resultante.

memoria:

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

"Dog" se recupera, ya que hay más punteros se conectan a ella es parte de la memoria. Nunca modificamos la sección de memoria "Dog" en la que residía, que es lo que significa inmutable. Sin embargo, podemos cambiar qué etiquetas, si las hay, apuntan a esa sección de la memoria.

23

La variable a apunta al objeto "Perro". Lo mejor es pensar en la variable en Python como una etiqueta. Puede mover la etiqueta a diferentes objetos, que es lo que hizo cuando cambió a = "dog" a a = "dog eats treats".

Sin embargo, la inmutabilidad se refiere al objeto, no a la etiqueta.


Si ha intentado hacer a[1] = 'z'"dog" en "dzg", se obtendría el error:

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

porque las cadenas no son compatibles con la asignación artículo, por lo que son inmutables.

+0

¡Este es más claro en comparación con otros! –

0

En resumen:

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

no es inmutable:

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

inmutable:

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

Esto es un error en Python 3, ya que es inmutable. Y no es un error en Python 2 porque claramente no es inmutable.

11

Algo se puede modificar solo cuando podemos cambiar los valores almacenados en la ubicación de la memoria sin cambiar la ubicación de la memoria.

El truco es: Si encuentra que la ubicación de la memoria antes y después del cambio es la misma, es mutable.

Por ejemplo, la lista es mutable. ¿Cómo?

>> 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 secuencia es inmutable. ¿Cómo lo probamos?

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

obtenemos

TypeError: 'str' object does not support item assignment

Así que fallaron mutación de la cadena. Significa que una cuerda es inmutable.

Al reasignar, cambia la variable para que apunte a una nueva ubicación. Aquí no ha mutado la cuerda, sino mutando la variable en sí. Lo siguiente es lo que estás haciendo.

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

id antes y después de la reasignación es diferente, por lo que esto demuestra que en realidad no mutando, pero señalando la variable a la nueva ubicación. Lo cual no está mutando esa cuerda, sino mutando esa variable.

1

>>> a = 'dogs'

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

'dogs eat treats'

>>> print a

'dogs'

inmutable, no ?!

La parte de cambio de variable ya ha sido discutida.

+0

Esto no está probando o desaprobando la mutabilidad de cadenas de python, solo que el método 'replace()' devuelve una nueva cadena. –

4

considerar:

>>> 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> 

en cuenta que la ubicación de memoria hexagonal no cambió cuando almacenó el mismo valor en la variable dos veces. Cambió cuando almacené un valor diferente. La cuerda es inmutable. No por fanatismo, sino porque paga la penalidad de rendimiento de crear un nuevo objeto en la memoria. La variable a es solo una etiqueta que apunta a esa dirección de memoria. Puede ser alterado para apuntar a cualquier cosa.

2

Las variables pueden apuntar a cualquier lugar que desee .. un error se produce si hace lo siguiente:

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

considerar esta adición a su ejemplo

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 

Uno de los más precisos las explicaciones que encontré en un blog son:

In Python, (almost) everything is an object. What we commonly refer to as "variables" in Python are more properly called names. Likewise, "assignment" is really the binding of a name to an object. Each binding has a scope that defines its visibility, usually the block in which the name originates.

Eg:

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

When we later say some_guy = 'George', the string object containing 'Fred' is unaffected. We've just changed the binding of the name some_guy. We haven't, however, changed either the 'Fred' or 'George' string objects. As far as we're concerned, they may live on indefinitely.

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

0

se puede hacer una variedad numpy inmutable y utilizar el primer elemento:

numpyarrayname[0] = "write once" 

a continuación:

numpyarrayname.setflags(write=False) 

o

numpyarrayname.flags.writeable = False 
Cuestiones relacionadas