Tipos inmutables vs mutables


186

Estoy confundido sobre lo que es un tipo inmutable. Sé que el floatobjeto 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 floatestá 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 dictes 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 examplemétodo, devuelve un diccionario. El SortedKeyDictcon lo __new__marca como un error. Intenté pasar enteros a la RoundFloatclase con __new__y no marcó ningún error.


También puede consultar la asignación de lista con [:] y python cuando usar copy.copy, que también respondí para obtener más información sobre la mutabilidad.
AGF

Respuestas:


232

¿Qué? Los flotadores son inmutables? Pero no puedo hacer

x = 5.0
x += 7.0
print x # 12.0

¿No es eso "mut" x?

Bueno, estás de acuerdo en que las cadenas son inmutables, ¿verdad? Pero puedes hacer lo mismo.

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

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.

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

Ejemplos concretos

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]

55
Lo que usted explica significa para mí: las variables mutables se pasan por referencia, las variables inmutables se pasan por valor. Es esto correcto ?
Lorenz Meyer

17
Casi, pero no exactamente. Técnicamente, todas las variables se pasan por referencia en Python, pero tienen una semántica más como pasar por valor en C. Un contraejemplo a su analogía es si lo hace 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.
morningstar

66
Los tipos mutables se pueden cambiar en su lugar. Los tipos inmutables no pueden cambiar en su lugar. Así es como Python ve el mundo. Es independientemente de cómo se pasan las variables a las funciones.
ychaouche

13
La diferencia clave entre la semántica de Python y la semántica de paso por referencia de C ++ es que la asignación no es mutación en Python, y está en C ++. (Pero, por supuesto, eso es complicado por el hecho de que la asignación aumentada, como a a += bveces 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] = bno muta a[0], pero probablemente mute a... 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 ...)
abarnert

2
Encontré esta respuesta engañosa porque no usa id (), que es esencial para comprender lo que significa inmutable.
pawel_winzig

185

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 TypeErrorsi intentas cambiarlo. Además, si asignamos nuevo contenido, se crea un nuevo objeto en lugar de modificar el contenido.

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

Puede hacerlo con una lista y no cambiará la identidad de los objetos.

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

Para leer más sobre el modelo de datos de Python, puede echar un vistazo a la referencia del lenguaje Python:


44
+1 Para el enlace a los documentos de Python. Sin embargo, me tomó un tiempo hasta que me di cuenta de que hoy necesitas diferenciar entre Python 2 y 3: actualicé la respuesta para enfatizar eso.
benjamin

107

Tipo inmutable común:

  1. números: int(), float(),complex()
  2. secuencias inmutables: str(), tuple(), frozenset(),bytes()

Tipo mutable común (casi todo lo demás):

  1. secuencias mutables: list(),bytearray()
  2. tipo de conjunto: set()
  3. tipo de mapeo: dict()
  4. clases, instancias de clase
  5. etc.

Un truco para probar rápidamente si un tipo es mutable o no es utilizar la id()función incorporada.

Ejemplos, usando en entero,

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

usando en la lista,

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

11
Bien explicado. Me gustó el concepto de verificar id(). +1.
Parag Tyagi

44
En realidad, el uso de 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.
augurar el

37

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.

ints y floats son inmutables . Si lo hago

a = 1
a += 5

Apunta el nombre aa un 1lugar en la memoria en la primera línea. En la segunda línea, busca que 1, agrega 5, obtiene 6, luego señala aeso 6en la memoria: no cambió el 1a a 6de ninguna manera. La misma lógica se aplica a los siguientes ejemplos, utilizando otros tipos inmutables :

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

Para los tipos mutables , puedo hacer algo que cambie realmente el valor donde está almacenado en la memoria . Con:

d = [1, 2, 3]

He creado una lista de las ubicaciones de 1, 2y 3en la memoria. Si entonces lo hago

e = d

Solo señalo elos mismoslist d puntos en. Entonces puedo hacer:

e += [4, 5]

Y la lista en la que tanto ey dpuntos se actualizarán para tener también las ubicaciones de 4y 5en la memoria.

Si vuelvo a un tipo inmutable y hago eso con un tuple:

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

Entonces ftodavía solo apunta al originaltuple : has señalado guno completamente nuevotuple .

Ahora, con tu ejemplo de

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

Por donde pasas

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

(que es una tuplede las tuples) como val, que está recibiendo un error porque tuples no tienen un .clear()método - que tendría que pasar dict(d)como valpara que funcione, en cuyo caso se obtendrá un vacío SortedKeyDictcomo resultado.


2
Esta es una muy buena explicación. Me encantó esta pregunta y muchas perspectivas (nuevas) interesantes para explicarla.
Error científico el

25

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:

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

En Python, la asignación no es mutación en Python.

En C ++, si escribe a = 2, está llamando a.operator=(2), lo que mutará el objeto almacenado a. (Y si no había ningún objeto almacenado a, es un error).

En Python, a = 2no hace nada a lo que sea que esté almacenado a; solo significa que 2ahora está almacenado en su alugar. (Y si no había ningún objeto almacenado a, 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 aes un int, eso significa que son 4 bytes en algún lugar que el compilador sabe que se debe interpretar como un int. Entonces, cuando lo hace a = 2, cambia lo que está almacenado en esos 4 bytes de memoria de 0, 0, 0, 1a 0, 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 1y otro objeto para el número 2. Y ano son 4 bytes de memoria que se representan como un int, es solo un nombre que apunta al 1objeto. No tiene sentido a = 2convertir 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 hacer aolvidar el 1objeto y señalarlo 2.


Entonces, si la asignación no es una mutación, ¿qué es una mutación?

  • Llamar a un método documentado para mutar, como a.append(b). (Tenga en cuenta que estos métodos casi siempre regresan None). Los tipos inmutables no tienen tales métodos, los tipos mutables sí los tienen.
  • Asignación a una parte del objeto, como a.spam = bo a[0] = b. Los tipos inmutables no permiten la asignación a atributos o elementos, los tipos mutables generalmente permiten uno u otro.
  • Algunas veces usando asignación aumentada, como 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 (calculan a + b, luego asignan el resultado a a).

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] = bhace no mutan a[0](de nuevo, a diferencia de C ++), sino que lo hace mutar a(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.


2
Di a = 'hola'. a [0] = 'f' tendrá 'print a' print out 'fi' (¿Estoy en lo cierto hasta ahora?), así que cuando dices que no muta a [0], sino a, ¿qué significa eso? ? ¿Tiene [n] también su propio lugar ahora, y cambiar su valor lo señala a un valor diferente?
Daniel Springer

19

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, tupley str, 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 " :

El valor de algunos objetos puede cambiar. Se dice que los objetos cuyo valor puede cambiar son mutables; Los objetos cuyo valor no se puede modificar una vez que se crean se denominan inmutables.

(El valor de un objeto contenedor inmutable que contiene una referencia a un objeto mutable puede cambiar cuando se cambia el valor de este último; sin embargo, el contenedor todavía se considera inmutable, porque la colección de objetos que contiene no se puede cambiar. Por lo tanto, la inmutabilidad no es estrictamente lo mismo que tener un valor inmutable, es más sutil).

La mutabilidad de un objeto está determinada por su tipo; por ejemplo, los números, las cadenas y las tuplas son inmutables, mientras que los diccionarios y las listas son mutables.


+1 Tenga en cuenta que solo algunos tipos de extensión (es posible que desee revisar su definición de eso, todos los tipos incorporados de Python se implementan en C) son inmutables. Otros (la mayoría, me atrevería a decir) son perfectamente mutables.

@delnan ¿Cómo se llama "tipos de extensiones" ?
eyquem

@eyquem: usé el término "tipos de extensión" incorrectamente en mi respuesta, y delnan se refería a eso. Después de su comentario revisé mi respuesta y evité usar este término.
taleinat

19

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:

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

Objetos inmutables

Aquí están los objetos en Python que son de tipo inmutable:

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

Algunas preguntas sin respuesta

Preguntas : ¿Es la cadena un tipo inmutable?
Respuesta : , pero puede explicar esto: Prueba 1 :

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

Salida

"Hello World"

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.

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

Salida

String is Immutable

Prueba 2 :

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

Salida

TypeError 'str' object does not support item assignment

Preguntas : ¿Es Tuple un tipo inmutable?
Respuesta : , lo es. Prueba 1 :

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

Salida

'tuple' object does not support item assignment

En [46]: a = "Hola" En [47]: id (a) Fuera [47]: 140071263880128 En [48]: a = a.replace ("H", "g") En [49]: a Salida [49]: 'gello' Entrada [50]: id (a) Salida [50]: 140071263881040
Argus Malware

¿le gustaría probar su problema de asignación de elementos a mi ejemplo anterior
Argus Malware

la asignación de elementos no se emite en tipos inmutables En su caso, está cambiando la cadena a pero en memoria se está asignando a una nueva variable. La asignación de elementos en mi caso no cambiará la memoria de la variable como en el caso de la lista o el diccionario. si está reemplazando, está creando una nueva variable que no modifica la variable existente
anand tripathi

@ArgusMalware en su caso, dos ID son iguales debido al primero reciclado por GC, por lo que el segundo reutiliza la memoria.
Colonler

11

Un objeto mutable debe tener al menos un método capaz de mutar el objeto. Por ejemplo, el listobjeto tiene el appendmétodo, que en realidad mutará el objeto:

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

pero la clase floatno tiene método para mutar un objeto flotante. Tu puedes hacer:

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

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.1el =operando, la variable se une a un nuevo flotante, que se crea con el resultado de 5 + 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ás

En 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 la 1.0parte de la línea. En realidad, cuando escribe 1.0es una abreviatura para float(1.0)una llamada de constructor que devuelve un objeto flotante. (Esa es la razón por la que si escribe 1.0y presiona Intro obtendrá el "eco" 1.0impreso a continuación; ese es el valor de retorno de la función constructora que llamó)

Ahora, si bes un flotador y usted asigna a = 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 hace b += 1, ahora bapunte a un nuevo objeto, y aes sigo señalando al viejo y no puedo saber a qué bestá apuntando.

pero si ces, digamos, a list, y usted asigna a = c, ahora ay cpuede "comunicarse", porque listes mutable, y si lo hace c.append('msg'), simplemente verificando aque 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).


6

Una clase es inmutable si cada objeto de esa clase tiene un valor fijo en la instanciación que no puede cambiarse SUBSECUENTEMENTE

En otra palabra, cambie el valor completo de esa variable (name)o déjelo solo.

Ejemplo:

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

esperaba que esto funcionara e imprimiera hello world pero esto arrojará el siguiente error:

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

El intérprete dice: no puedo cambiar el primer carácter de esta cadena

Tendrás que cambiar el todo stringpara que funcione:

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

mira esta tabla:

ingrese la descripción de la imagen aquí

fuente


¿Cómo se pueden modificar los componentes de una cadena de Python de una manera más concisa que la que se mostró anteriormente?
Luke Davis el

@LukeDavis Podrías hacer my_string = 'h' + my_string[1:]. Esto generará una nueva cadena llamada my_string, y my_string original desaparecerá (imprima id(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)
danio

5

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.


5

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?

  • escalares (tipos de variables que almacenan un solo valor) no cambian inesperadamente
    • ejemplos numéricos: int (), float (), complex ()
  • hay algunas "secuencias mutables":
    • str (), tuple (), frozenset (), bytes ()

¿Qué puede?

  • lista como objetos (listas, diccionarios, conjuntos, bytearray ())
  • una publicación aquí también dice clases e instancias de clase, pero esto puede depender de lo que la clase hereda y / o cómo se construye.

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?

  • Hay algunas pruebas dadas en otros comentarios en este hilo, pero luego hay comentarios que indican que estas pruebas no son prueba completa
  • object.function () es un método del objeto original pero solo algunos de estos mutan. Si no devuelven nada, probablemente lo hagan. Uno esperaría que .append () mute sin probarlo dado su nombre. .union () devuelve la unión de set1.union (set2) y no muta. En caso de duda, la función puede verificarse para obtener un valor de retorno. Si return = None, no muta.
  • sorted () puede ser una solución en algunos casos. Como devuelve una versión ordenada del original, puede permitirle almacenar una copia no mutada antes de comenzar a trabajar en el original de otras maneras. Sin embargo, esta opción supone que no le importa el orden de los elementos originales (si lo hace, necesita encontrar otra forma). Por el contrario .sort () muta el original (como cabría esperar).

Enfoques no estándar (en caso de ser útil): Encontré esto en github publicado bajo una licencia MIT

  • repositorio de github bajo: tobgu llamado: pyrsistent
  • Qué es: código de estructura de datos persistente de Python escrito para ser utilizado en lugar de estructuras de datos centrales cuando la mutación no es deseable

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.


3

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


1
Esto es incorrecto. Todas las asignaciones en Python son por referencia. No hay copia involucrada.
augurar

3

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:

>>>x = 5

Creará un valor 5 referenciado por x

x -> 5

>>>y = x

Esta declaración hará que y se refiera a 5 de x

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

>>>x = x + 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


-1

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

a = [1,2]

Si fueras a decir:

b = a
b[1] = 3

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.


-1

Para objetos inmutables, la asignación crea una nueva copia de valores, por ejemplo.

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)

Para objetos mutables, la asignación no crea otra copia de valores. Por ejemplo,

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
Absolutamente incorrecto La asignación nunca crea una copia . Lea nedbatchelder.com/text/names.html. En el primer caso, x=10es simplemente otra tarea , mientras que x[2] = 5llama a un método de mutación. intlos objetos simplemente carecen de métodos mutantes , pero la semántica de la asignación de python no depende del tipo
juanpa.arrivillaga

-2

En Python, hay una manera fácil de saber:

Inmutable:

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

Mudable:

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

Y:

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

Así que creo que la función incorporada también es inmutable en Python.

Pero realmente no entiendo cómo funciona el flotador:

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

Es tan raro.


Pero eso claramente no es válido. Porque las tuplas son inmutables. Escriba x = (1, 2)y luego intente y mute x, no es posible. Una forma en que he encontrado para verificar la mutabilidad es hashque funciona para los objetos incorporados al menos. hash(1) hash('a') hash((1, 2)) hash(True)todo funciona y hash([]) hash({}) hash({1, 2})no todos funcionan.
punto

@semicolon Para las clases definidas por el usuario, entonces hash()funcionará si el objeto define un __hash__()método, aunque las clases definidas por el usuario son generalmente mutables.
augurar

1
@augurar Quiero decir que sí, pero nada en Python garantizará nada, porque Python no tiene tipeo estático real ni garantías formales. Pero el hashmé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.
punto

1
@augurar y punto y coma (u otros si lo saben): solución __hash __ () ... ¿el creador de una clase personalizada tiene que agregarlo para que esté allí? Si es así, entonces la regla es si existe el objeto debe ser inmutable; Si no existe, no podemos saberlo, ya que el creador puede simplemente haberse ido si está apagado.
TMWP
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.