tipos - que es una tupla en python
¿Las cadenas de Python no son inmutables? Entonces, ¿por qué funciona un+""+b? (17)
Añadiendo un poco más a las respuestas mencionadas anteriormente.
id
de una variable cambia con la reasignación.
>>> a = ''initial_string''
>>> id(a)
139982120425648
>>> a = ''new_string''
>>> id(a)
139982120425776
Lo que significa que hemos mutado la variable a
para apuntar a una nueva cadena. Ahora existen dos objetos de string
(str):
''initial_string''
con id
= 139982120425648
y
''new_string''
con id
= 139982120425776
Considere el siguiente código:
>>> b = ''intitial_string''
>>> id(b)
139982120425648
Ahora, b
apunta a ''initial_string''
y tiene el mismo id
que tenía antes de la reasignación.
Por lo tanto, la ''intial_string''
no ha sido mutada.
Según entendí, las cadenas de Python son inmutables.
Probé 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 Python haber evitado la asignación? Probablemente me esté perdiendo algo.
¿Alguna idea?
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 cuerda es inmutable. ¿Cómo lo probamos?
> a = "hello"
> a[0]
''h''
# Now let''s modify it
> a[0] = ''n''
----------------------------------------------------------------------
obtenemos
TypeError: el objeto ''str'' no admite la asignación de elementos
Así que fallamos al mutar la cuerda. 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 prueba que en realidad no está mutando, sino que apunta la variable a una nueva ubicación. Lo cual no está mutando esa cuerda, sino mutando esa variable.
Considera esta adición a tu 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
Una de las explicaciones más precisas que encontré en un blog es:
En Python, (casi) todo es un objeto. A lo que comúnmente nos referimos como "variables" en Python se les llama más propiamente nombres. Del mismo modo, "asignación" es realmente la unión de un nombre a un objeto. Cada enlace tiene un alcance que define su visibilidad, generalmente el bloque en el que se origina el nombre.
P.ej:
some_guy = ''Fred''
# ...
some_guy = ''George''
Cuando más tarde decimos some_guy = ''George'', el objeto de cadena que contiene ''Fred'' no se ve afectado. Acabamos de cambiar el enlace del nombre some_guy. Sin embargo, no hemos cambiado los objetos de cadena ''Fred'' o ''George''. En lo que a nosotros respecta, pueden vivir indefinidamente.
Enlace al blog: https://jeffknupp.com/blog/2012/11/13/is-python-callbyvalue-or-callbyreference-neither/
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>
Observe que la ubicación de la memoria hexadecimal 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.
Hay una diferencia entre los datos y la etiqueta a la que está asociada. Por ejemplo, cuando lo haces
a = "dog"
el "dog"
datos se crea y se coloca bajo la etiqueta a
. La etiqueta puede cambiar, pero lo que está en la memoria no lo hará. El "dog"
datos seguirá existiendo en la memoria (hasta que el recolector de basura lo elimine) después de que lo haga
a = "cat"
En su programa, a
ahora ^ apunta a ^ "cat"
pero la cadena "dog"
no ha cambiado.
La declaración a = a + " " + b + " " + c
se puede desglosar según punteros.
a + " "
dice: dame lo que apunta, 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 que b
señala, que no se puede cambiar, y agrégalo al conjunto de trabajo actual.
memoria:
working_set = "Dog eats"
a = "Dog"
b = "eats"
c = "treats"
+ " " + c
dice agregar " "
al conjunto actual. Luego, dame lo que c
señala, 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"
Finalmente, a =
dice que mi puntero apunta al conjunto resultante.
memoria:
a = "Dog eats treats"
b = "eats"
c = "treats"
"Dog"
porque no hay más punteros conectados a su pedazo de memoria. Nunca modificamos la sección de memoria en la que residía "Dog"
, que es lo que significa inmutable. Sin embargo, podemos cambiar qué etiquetas, si las hay, apuntan a esa sección de la memoria.
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 "dzg"
a[1] = ''z''
para convertir a "dog"
en "dzg"
, obtendrías el siguiente error:
TypeError: ''str'' object does not support item assignment"
porque las cadenas no admiten la asignación de elementos, por lo tanto, son inmutables.
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.
Las variables pueden apuntar a cualquier lugar que deseen .. Se lanzará un error si hace lo siguiente:
a = "dog"
print a #dog
a[1] = "g" #ERROR!!!!!! STRINGS ARE IMMUTABLE
Los objetos de cadena de Python son inmutables. Ejemplo:
>>> 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''
En este ejemplo, podemos ver que cuando asignamos un valor diferente en a no se modifica. Se crea un nuevo objeto.
Y no puede ser modificado. Ejemplo:
>>> a[0] = ''c''
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
**TypeError**: ''str'' object does not support item assignment
Se produce un error
Los objetos de cuerda en sí mismos 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.
Primero apunte a la cuerda "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.
Puedes hacer que una matriz numpy sea inmutable y usar el primer elemento:
numpyarrayname[0] = "write once"
entonces:
numpyarrayname.setflags(write=False)
o
numpyarrayname.flags.writeable = False
Resumiendo:
a = 3
b = a
a = 3+2
print b
# 5
No 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
Este es un error en Python 3 porque es inmutable. Y no es un error en Python 2 porque claramente no es inmutable.
Una variable es solo 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.
>>> 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.
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