Estoy confundido sobre lo que es un tipo inmutable. Sé que el float
objeto se considera inmutable, con este tipo de ejemplo de mi libro:
class RoundFloat(float):
def __new__(cls, val):
return float.__new__(cls, round(val, 2))
¿Se considera que esto es inmutable debido a la estructura / jerarquía de la clase ?, el significado float
está en la parte superior de la clase y es su propia llamada al método. Similar a este tipo de ejemplo (aunque mi libro dice que dict
es mutable):
class SortedKeyDict(dict):
def __new__(cls, val):
return dict.__new__(cls, val.clear())
Mientras que algo mutable tiene métodos dentro de la clase, con este tipo de ejemplo:
class SortedKeyDict_a(dict):
def example(self):
return self.keys()
Además, para el último class(SortedKeyDict_a)
, si le paso este tipo de conjunto:
d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))
sin llamar al example
método, devuelve un diccionario. El SortedKeyDict
con lo __new__
marca como un error. Intenté pasar enteros a la RoundFloat
clase con __new__
y no marcó ningún error.
python
immutability
mutable
usuario1027217
fuente
fuente
Respuestas:
¿Qué? Los flotadores son inmutables? Pero no puedo hacer
¿No es eso "mut" x?
Bueno, estás de acuerdo en que las cadenas son inmutables, ¿verdad? Pero puedes hacer lo mismo.
El valor de la variable cambia, pero cambia cambiando a qué se refiere la variable. Un tipo mutable puede cambiar de esa manera, y puede también cambiar "en su lugar".
Aquí está la diferencia.
Ejemplos concretos
fuente
def f(my_list): my_list = [1, 2, 3]
. Con paso por referencia en C, el valor del argumento podría cambiar llamando a esa función. En Python, esa función no hace nada.def f(my_list): my_list[:] = [1, 2, 3]
Haría algo.a += b
veces es mutación. Y el hecho de que la asignación a parte de un objeto más grande a veces significa mutación de ese objeto más grande, simplemente nunca mutación de la parte, por ejemplo,a[0] = b
no mutaa[0]
, pero probablemente mutea
... Es por eso que puede ser mejor no tratar de poner las cosas en términos de C ++ y simplemente describir lo que hace Python en sus propios términos ...)Tienes que entender que Python representa todos sus datos como objetos. Algunos de estos objetos, como listas y diccionarios, son mutables, lo que significa que puede cambiar su contenido sin cambiar su identidad. Otros objetos como enteros, flotantes, cadenas y tuplas son objetos que no se pueden cambiar. Una manera fácil de entender eso es si observa un ID de objeto.
A continuación, verá una cadena que es inmutable. No puedes cambiar su contenido. Aparecerá un
TypeError
si intentas cambiarlo. Además, si asignamos nuevo contenido, se crea un nuevo objeto en lugar de modificar el contenido.Puede hacerlo con una lista y no cambiará la identidad de los objetos.
Para leer más sobre el modelo de datos de Python, puede echar un vistazo a la referencia del lenguaje Python:
fuente
Tipo inmutable común:
int()
,float()
,complex()
str()
,tuple()
,frozenset()
,bytes()
Tipo mutable común (casi todo lo demás):
list()
,bytearray()
set()
dict()
Un truco para probar rápidamente si un tipo es mutable o no es utilizar la
id()
función incorporada.Ejemplos, usando en entero,
usando en la lista,
fuente
id()
. +1.id()
es engañoso aquí. Un objeto dado siempre tendrá la misma identificación durante su vida útil, pero diferentes objetos que existen en diferentes momentos pueden tener la misma identificación debido a la recolección de basura.En primer lugar, si una clase tiene métodos o cuál es su estructura de clase no tiene nada que ver con la mutabilidad.
int
s yfloat
s son inmutables . Si lo hagoApunta el nombre
a
a un1
lugar en la memoria en la primera línea. En la segunda línea, busca que1
, agrega5
, obtiene6
, luego señalaa
eso6
en la memoria: no cambió el1
a a6
de ninguna manera. La misma lógica se aplica a los siguientes ejemplos, utilizando otros tipos inmutables :Para los tipos mutables , puedo hacer algo que cambie realmente el valor donde está almacenado en la memoria . Con:
He creado una lista de las ubicaciones de
1
,2
y3
en la memoria. Si entonces lo hagoSolo señalo
e
los mismoslist
d
puntos en. Entonces puedo hacer:Y la lista en la que tanto
e
yd
puntos se actualizarán para tener también las ubicaciones de4
y5
en la memoria.Si vuelvo a un tipo inmutable y hago eso con un
tuple
:Entonces
f
todavía solo apunta al originaltuple
: has señaladog
uno completamente nuevotuple
.Ahora, con tu ejemplo de
Por donde pasas
(que es una
tuple
de lastuples
) comoval
, que está recibiendo un error porquetuple
s no tienen un.clear()
método - que tendría que pasardict(d)
comoval
para que funcione, en cuyo caso se obtendrá un vacíoSortedKeyDict
como resultado.fuente
Si viene a Python desde otro idioma (excepto uno que es muy parecido a Python, como Ruby), e insiste en entenderlo en términos de ese otro idioma, aquí es donde la gente generalmente se confunde:
En Python, la asignación no es mutación en Python.
En C ++, si escribe
a = 2
, está llamandoa.operator=(2)
, lo que mutará el objeto almacenadoa
. (Y si no había ningún objeto almacenadoa
, es un error).En Python,
a = 2
no hace nada a lo que sea que esté almacenadoa
; solo significa que2
ahora está almacenado en sua
lugar. (Y si no había ningún objeto almacenadoa
, está bien).En última instancia, esto es parte de una distinción aún más profunda.
Una variable en un lenguaje como C ++ es una ubicación escrita en la memoria. Si
a
es unint
, eso significa que son 4 bytes en algún lugar que el compilador sabe que se debe interpretar como unint
. Entonces, cuando lo hacea = 2
, cambia lo que está almacenado en esos 4 bytes de memoria de0, 0, 0, 1
a0, 0, 0, 2
. Si hay otra variable int en otro lugar, tiene sus propios 4 bytes.Una variable en un lenguaje como Python es un nombre para un objeto que tiene vida propia. Hay un objeto para el número
1
y otro objeto para el número2
. Ya
no son 4 bytes de memoria que se representan como unint
, es solo un nombre que apunta al1
objeto. No tiene sentidoa = 2
convertir el número 1 en el número 2 (eso le daría a cualquier programador de Python demasiado poder para cambiar el funcionamiento fundamental del universo); lo que hace es hacera
olvidar el1
objeto y señalarlo2
.Entonces, si la asignación no es una mutación, ¿qué es una mutación?
a.append(b)
. (Tenga en cuenta que estos métodos casi siempre regresanNone
). Los tipos inmutables no tienen tales métodos, los tipos mutables sí los tienen.a.spam = b
oa[0] = b
. Los tipos inmutables no permiten la asignación a atributos o elementos, los tipos mutables generalmente permiten uno u otro.a += b
, otras veces no. Los tipos mutables generalmente mutan el valor; los tipos inmutables nunca lo hacen, y en su lugar le dan una copia (calculana + b
, luego asignan el resultado aa
).Pero si la asignación no es mutación, ¿cómo se asigna a parte de la mutación del objeto? Ahí es donde se pone difícil.
a[0] = b
hace no mutana[0]
(de nuevo, a diferencia de C ++), sino que lo hace mutara
(a diferencia de C ++, salvo de manera indirecta).Todo esto es la razón por la que probablemente sea mejor no tratar de poner la semántica de Python en términos de un idioma al que estás acostumbrado, y en su lugar aprender la semántica de Python en sus propios términos.
fuente
Si un objeto es mutable o no depende de su tipo. Esto no depende de si tiene o no ciertos métodos, ni de la estructura de la jerarquía de clases.
Los tipos definidos por el usuario (es decir, las clases) son generalmente mutables. Hay algunas excepciones, como subclases simples de un tipo inmutable. Otros tipos inmutables incluyen algunos tipos incorporados tales como
int
,float
,tuple
ystr
, así como algunas clases de Python implementados en C.Una explicación general del capítulo "Modelo de datos" en la Referencia del lenguaje Python " :
fuente
Diferencia entre objetos mutables e inmutables
Definiciones
Objeto mutable : objeto que se puede cambiar después de crearlo.
Objeto inmutable : objeto que no se puede cambiar después de crearlo.
En python, si cambia el valor del objeto inmutable, creará un nuevo objeto.
Objetos mutables
Aquí están los objetos en Python que son de tipo mutable:
list
Dictionary
Set
bytearray
user defined classes
Objetos inmutables
Aquí están los objetos en Python que son de tipo inmutable:
int
float
decimal
complex
bool
string
tuple
range
frozenset
bytes
Algunas preguntas sin respuesta
Preguntas : ¿Es la cadena un tipo inmutable?
Respuesta : sí , pero puede explicar esto: Prueba 1 :
Salida
En el ejemplo anterior, la cadena se creó una vez como "Hola" y luego cambió a "Hola Mundo". Esto implica que la cadena es del tipo mutable. Pero no es así cuando verificamos su identidad para ver si es de tipo mutable o no.
Salida
Prueba 2 :
Salida
Preguntas : ¿Es Tuple un tipo inmutable?
Respuesta : sí , lo es. Prueba 1 :
Salida
fuente
Un objeto mutable debe tener al menos un método capaz de mutar el objeto. Por ejemplo, el
list
objeto tiene elappend
método, que en realidad mutará el objeto:pero la clase
float
no tiene método para mutar un objeto flotante. Tu puedes hacer:pero el
=
operando no es un método. Simplemente hace un enlace entre la variable y lo que está a su derecha, nada más. Nunca cambia ni crea objetos. Es una declaración de lo que señalará la variable, desde ahora en adelante.Cuando haces
b = b + 0.1
el=
operando, la variable se une a un nuevo flotante, que se crea con el resultado de5 + 0.1
.Cuando asigna una variable a un objeto existente, mutable o no, el
=
operando une la variable a ese objeto. Y no pasa nada másEn cualquier caso,
=
solo hacen el enlace. No cambia ni crea objetos.Cuando lo hace
a = 1.0
, el=
operando no es el que crea el flotador, sino la1.0
parte de la línea. En realidad, cuando escribe1.0
es una abreviatura parafloat(1.0)
una llamada de constructor que devuelve un objeto flotante. (Esa es la razón por la que si escribe1.0
y presiona Intro obtendrá el "eco"1.0
impreso a continuación; ese es el valor de retorno de la función constructora que llamó)Ahora, si
b
es un flotador y usted asignaa = b
, ambas variables están apuntando al mismo objeto, pero en realidad las variables no pueden comunicarse entre sí, porque el objeto es inmutable, y si lo haceb += 1
, ahorab
apunte a un nuevo objeto, ya
es sigo señalando al viejo y no puedo saber a québ
está apuntando.pero si
c
es, digamos, alist
, y usted asignaa = c
, ahoraa
yc
puede "comunicarse", porquelist
es mutable, y si lo hacec.append('msg')
, simplemente verificandoa
que reciba el mensaje.(Por cierto, cada objeto tiene un número de identificación único asociado, con el que puede obtener
id(x)
. Por lo tanto, puede verificar si un objeto es el mismo o no, si su identificación única ha cambiado).fuente
En otra palabra, cambie el valor completo de esa variable
(name)
o déjelo solo.Ejemplo:
esperaba que esto funcionara e imprimiera hello world pero esto arrojará el siguiente error:
El intérprete dice: no puedo cambiar el primer carácter de esta cadena
Tendrás que cambiar el todo
string
para que funcione:mira esta tabla:
fuente
fuente
my_string = 'h' + my_string[1:]
. Esto generará una nueva cadena llamada my_string, y my_string original desaparecerá (imprimaid(my_string)
para ver esto). Por supuesto, eso no es muy flexible, para el caso más general, puede convertir a la lista y viceversa:l = list(my_string)
l[0] = 'h'
my_string = ''.join(l)
Me parece que estás luchando con la pregunta de lo que realmente significa mutable / inmutable . Así que aquí hay una explicación simple:
Primero necesitamos una base para basar la explicación.
Así que piense en cualquier cosa que programe como un objeto virtual, algo que se guarda en la memoria de una computadora como una secuencia de números binarios. (Sin embargo, no trate de imaginar esto demasiado duro. ^^) Ahora, en la mayoría de los lenguajes de computadora, no trabajará con estos números binarios directamente, sino que más bien utilizará una interpretación de los números binarios.
Por ejemplo, no piensa en números como 0x110, 0xaf0278297319 o similares, sino que piensa en números como 6 o cadenas como "Hola, mundo". Sin embargo, estos números o cadenas son una interpretación de un número binario en la memoria de la computadora. Lo mismo es cierto para cualquier valor de una variable.
En resumen: Nosotros no programa con valores reales, pero con interpretaciones de valores binarios reales.
Ahora tenemos interpretaciones que no deben cambiarse por lógica y otras "cosas buenas", mientras que hay interpretaciones que bien pueden cambiarse. Por ejemplo, piense en la simulación de una ciudad, en otras palabras, un programa donde hay muchos objetos virtuales y algunos de estos son casas. Ahora, ¿pueden cambiarse estos objetos virtuales (las casas) y todavía pueden considerarse como las mismas casas? Bueno, por supuesto que pueden. Por lo tanto, son mutables: se pueden cambiar sin convertirse en un objeto "completamente" diferente.
Ahora piense en enteros: estos también son objetos virtuales (secuencias de números binarios en la memoria de una computadora). Entonces, si cambiamos uno de ellos, como incrementar el valor seis por uno, ¿sigue siendo un seis? Pues claro que no. Por lo tanto, cualquier número entero es inmutable.
Entonces: si cualquier cambio en un objeto virtual significa que en realidad se convierte en otro objeto virtual, entonces se llama inmutable.
Observaciones finales:
(1) Nunca mezcle su experiencia en el mundo real de mutable e inmutable con la programación en un lenguaje determinado:
Cada lenguaje de programación tiene una definición propia sobre qué objetos pueden silenciarse y cuáles no.
Entonces, si bien ahora puede comprender la diferencia de significado, aún debe aprender la implementación real de cada lenguaje de programación. ... De hecho, podría haber un propósito de un lenguaje en el que un 6 puede silenciarse para convertirse en un 7. Por otra parte, esto sería algo bastante loco o interesante, como simulaciones de universos paralelos. ^^
(2) Esta explicación ciertamente no es científica, está destinada a ayudarlo a comprender la diferencia entre mutable e inmutable.
fuente
El objetivo de esta respuesta es crear un lugar único para encontrar todas las buenas ideas sobre cómo saber si se trata de mutantes / no mutantes (inmutables / mutables) y, cuando sea posible, ¿qué hacer al respecto? Hay momentos en que la mutación es indeseable y el comportamiento de Python a este respecto puede parecer contradictorio para los codificadores que ingresan desde otros idiomas.
Según una publicación útil de @ mina-gabriel:
Analizando lo anterior y combinando con una publicación de @ arrakëën:
¿Qué no puede cambiar inesperadamente?
¿Qué puede?
por "inesperadamente" quiero decir que los programadores de otros lenguajes podrían no esperar este comportamiento (con la excepción de Ruby, y quizás algunos otros lenguajes "similares a Python").
Agregando a esta discusión:
Este comportamiento es una ventaja cuando le impide llenar accidentalmente su código con múltiples copias de grandes estructuras de datos que consumen memoria. Pero cuando esto no es deseable, ¿cómo lo solucionamos?
Con listas, la solución simple es construir una nueva como esta:
lista2 = lista (lista1)
con otras estructuras ... la solución puede ser más complicada. Una forma es recorrer los elementos y agregarlos a una nueva estructura de datos vacía (del mismo tipo).
Las funciones pueden mutar el original cuando pasa en estructuras mutables. ¿Como decir?
Enfoques no estándar (en caso de ser útil): Encontré esto en github publicado bajo una licencia MIT
Para las clases personalizadas, @semicolon sugiere verificar si hay una
__hash__
función porque los objetos mutables generalmente no deberían tener una__hash__()
función.Esto es todo lo que he acumulado sobre este tema por ahora. Otras ideas, correcciones, etc. son bienvenidas. Gracias.
fuente
Una forma de pensar en la diferencia:
Las asignaciones a objetos inmutables en python pueden considerarse copias profundas, mientras que las asignaciones a objetos mutables son poco profundas
fuente
La respuesta más simple:
Una variable mutable es aquella cuyo valor puede cambiar en su lugar, mientras que en una variable inmutable el cambio de valor no ocurrirá en su lugar. La modificación de una variable inmutable reconstruirá la misma variable.
Ejemplo:
Creará un valor 5 referenciado por x
x -> 5
Esta declaración hará que y se refiera a 5 de x
x -------------> 5 <----------- y
Como x es un número entero (tipo inmutable) se ha reconstruido.
En la declaración, la expresión en RHS dará como resultado el valor 10 y cuando se asigne a LHS (x), x se reconstruirá a 10. Entonces ahora
x ---------> 10
y ---------> 5
fuente
No he leído todas las respuestas, pero la respuesta seleccionada no es correcta y creo que el autor tiene la idea de que poder reasignar una variable significa que cualquier tipo de datos es mutable. Ese no es el caso. La mutabilidad tiene que ver con pasar por referencia en lugar de pasar por valor.
Digamos que creaste una Lista
Si fueras a decir:
Aunque reasigne un valor en B, también reasignará el valor en a. Es porque cuando asignas "b = a". Está pasando la "Referencia" al objeto en lugar de una copia del valor. Este no es el caso con cadenas, flotantes, etc. Esto hace que la lista, los diccionarios y los gustos sean mutables, pero los booleanos, flotantes, etc., sean inmutables.
fuente
Para objetos inmutables, la asignación crea una nueva copia de valores, por ejemplo.
Para objetos mutables, la asignación no crea otra copia de valores. Por ejemplo,
fuente
x=10
es simplemente otra tarea , mientras quex[2] = 5
llama a un método de mutación.int
los objetos simplemente carecen de métodos mutantes , pero la semántica de la asignación de python no depende del tipoEn Python, hay una manera fácil de saber:
Inmutable:
Mudable:
Y:
Así que creo que la función incorporada también es inmutable en Python.
Pero realmente no entiendo cómo funciona el flotador:
Es tan raro.
fuente
x = (1, 2)
y luego intente y mutex
, no es posible. Una forma en que he encontrado para verificar la mutabilidad eshash
que funciona para los objetos incorporados al menos.hash(1)
hash('a')
hash((1, 2))
hash(True)
todo funciona yhash([])
hash({})
hash({1, 2})
no todos funcionan.hash()
funcionará si el objeto define un__hash__()
método, aunque las clases definidas por el usuario son generalmente mutables.hash
método sigue siendo bastante bueno, porque los objetos mutables generalmente no deberían tener un__hash__()
método, ya que convertirlos en claves en un diccionario es simplemente peligroso.