tutorial matplot datacamp python immutability mutable

matplot - python 2.7 plot



Tipos inmutables vs mutables (15)

Estoy confundido sobre lo que es un tipo inmutable. Sé que el objeto float 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 de clase / jerarquía ?, lo que significa que float está en la parte superior de la clase y es su propia llamada a 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 la última class(SortedKeyDict_a) , si le paso este tipo de conjunto:

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

sin llamar al método de example , devuelve un diccionario. SortedKeyDict con __new__ lo __new__ como un error. Intenté pasar enteros a la clase __new__ con __new__ y no marcó ningún error.


Una clase es inmutable si cada objeto de esa clase tiene un valor fijo en la creación de instancias que no se puede cambiar POSTERIORMENTE

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

esperabas que esto funcionara e imprimieras hola mundo, 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 caracter de esta cadena

Tendrás que cambiar toda la string para que funcione:

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

mira esta tabla:

source


Diferencia entre objeto mutable e inmutable

La definición genérica en python es:

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 intentará cambiar el valor del objeto inmutable que le dará al nuevo objeto.

Objetos mutables

Aquí está la lista de objetos en python que son de tipo mutable:

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

Objetos inmutables

Aquí está la lista de 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 : ¿La cuerda es un tipo inmutable?
Respuesta : lo es, pero ¿puedes explicar esto? Prueba 1 :

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

Salida

"Hello World"

En el ejemplo anterior, la cadena que se creó una vez como "Hola" finalmente cambió a "Hola mundo". Esto implica que la cadena es de tipo mutable. Pero no es así, podemos verificar su identidad y verificar 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 : , es la Prueba 1 :

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

Salida

''tuple'' object does not support item assignment


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

x = 5.0 x += 7.0 print x # 12.0

¿Eso no es "mut" x?

Bueno, usted acepta 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 al cambiar a qué se refiere la variable. Un tipo mutable puede cambiar de esa manera, y también puede 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]


El objetivo de esta respuesta es crear un solo lugar para encontrar todas las buenas ideas sobre cómo saber si se trata de mutar / no mutar (inmutable / mutable) y, cuando sea posible, ¿qué hacer al respecto? Hay momentos en que la mutación es indeseable y el comportamiento de Python en este sentido puede parecer contraintuitivo para los codificadores que ingresan desde otros lenguajes.

Según una publicación útil de @mina-gabriel:

  • Libros para leer que podrían ayudar: " source "
  • Extracto de ese libro que enumera tipos mutables / inmutables:

Analizando lo anterior y combinando la publicación w / a por @ arrakëën:

¿Qué no puede cambiar inesperadamente?

  • escalares (tipos 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 instancias de clases y clases, pero esto puede depender de lo que hereda la clase y / o cómo se construye.

por "inesperadamente" me refiero a que los programadores de otros lenguajes podrían no esperar este comportamiento (con la excepción de Ruby, y tal vez algunos otros lenguajes tipo "Python").

Agregando a esta discusión:

Este comportamiento es una ventaja cuando le impide rellenar accidentalmente su código con múltiples copias de grandes estructuras de datos que consumen memoria. Pero cuando esto es indeseable, ¿cómo lo solucionamos?

Con las listas, la solución simple es construir una nueva como esta:

list2 = list (list1)

con otras estructuras ... la solución puede ser más difícil. 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 pasas 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 a 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, se puede verificar la función de un valor de retorno. Si return = None, no mutea.
  • sorted () puede ser una solución alternativa 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 asume que no le importa el orden de los elementos originales (si lo hace, debe encontrar otra forma). En contraste, .sort () muta el original (como uno podría esperar).

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

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

Para clases personalizadas, @semicolon sugiere verificar si hay una función __hash__ porque los objetos mutables generalmente no deben tener una función __hash__() .

Esto es todo lo que he acumulado sobre este tema por ahora. Otras ideas, correcciones, etc. son bienvenidas. Gracias.


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.


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 y float s son inmutables . Si lo hago

a = 1 a += 5

Señala el nombre a en 1 en alguna parte de la memoria en la primera línea. En la segunda línea, busca que 1 , agregue 5 , obtenga 6 , luego apunte a ese 6 en memoria - no cambió el 1 a 6 de 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 el valor donde está almacenado en la memoria . Con:

d = [1, 2, 3]

Creé una lista de las ubicaciones de 1 , 2 y 3 en la memoria. Si yo lo hago

e = d

Simplemente apunto e a la misma list d puntos en. Entonces puedo hacer:

e += [4, 5]

Y la lista a la que se actualizarán tanto los puntos e como d también tendrá las ubicaciones de 4 y 5 en la memoria.

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

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

Luego, f solo apunta a la tuple original : has señalado una tuple completamente nueva .

Ahora, con tu ejemplo de

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

Donde pasa

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

(que es una tuple de tuples ) como val , está obteniendo un error porque las tuple no tienen un método .clear() - tendrías que pasar dict(d) como val para que funcione, en en ese caso obtendrá un SortedKeyDict vacío como resultado.


Me parece que estás luchando con la pregunta de qué significa mutable / inmutable en realidad . Entonces 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. (No trates de imaginar esto demasiado duro, sin embargo. ^^) Ahora en la mayoría de los lenguajes de computadora no trabajarás directamente con estos números binarios, sino que más bien usarás una interpretación de números binarios.

Por ejemplo, no piense en números como 0x110, 0xaf0278297319 o similar, sino que piense en números como 6 o en cadenas como "Hola, mundo". Sin embargo, estos números o cadenas son una interpretación de un número binario en la memoria de las computadoras. Lo mismo es cierto para cualquier valor de una variable.

En resumen: no programamos con valores reales, sino con interpretaciones de valores binarios reales.

Ahora tenemos interpretaciones que no deben cambiarse por el bien de la lógica y otras "cosas ordenadas", 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 ellos son casas. Ahora bien, ¿pueden cambiarse estos objetos virtuales (las casas) y aún se pueden considerar 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 de seis en uno, ¿sigue siendo un seis? Bueno, por supuesto que no. Por lo tanto, cualquier número entero es inmutable.

Entonces: si cualquier cambio en un objeto virtual significa que realmente se convierte en otro objeto virtual, entonces se llama inmutable.

Observaciones finales:

(1) Nunca mezcles tu experiencia de mutable e inmutable en el mundo real con la programación en un determinado idioma:

Cada lenguaje de programación tiene una definición propia en la que los objetos pueden silenciarse y cuáles no.

Entonces, si bien ahora puede comprender la diferencia en el significado, todavía tiene que aprender la implementación real para cada lenguaje de programación. ... De hecho, puede haber un propósito de un lenguaje en el que un 6 puede ser silenciado para convertirse en un 7. Entonces, de nuevo, esto sería bastante loco o algo interesante, como simulaciones de universos paralelos. ^^

(2) Esta explicación no es ciertamente científica, está destinada a ayudarlo a comprender la diferencia entre lo mutable y lo inmutable.


No he leído todas las respuestas, pero la respuesta seleccionada no es correcta y creo que el autor tiene una 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 has creado una lista

a = [1,2]

Si dijeras:

b = a b[1] = 3

Aunque reasignó un valor en B, también reasignará el valor en a. Es porque cuando asigna "b = a". Está pasando la "Referencia" al objeto en lugar de una copia del valor. Este no es el caso con cadenas, flotadores, etc. Esto hace que la lista, los diccionarios y los me gusta sean mutables, pero booleanos, flotantes, etc. inmutables.


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 tipo inmutable. Otros tipos inmutables incluyen algunos tipos incorporados como int , float , tuple y str , así como algunas clases de Python implementadas 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 cambiar una vez que se crean se llaman inmutables.

(El valor de un objeto de contenedor inmutable que contiene una referencia a un objeto mutable puede cambiar cuando se cambia el valor de este último, sin embargo, el contenedor aún se considera inmutable, porque la colección de objetos que contiene no puede modificarse. 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.


Si vienes a Python desde otro idioma (excepto uno que se parece mucho a Python, como Ruby), e insistes en entenderlo en términos de ese otro idioma, aquí es donde la gente suele confundirse:

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

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

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

En Python, a = 2 no hace nada con lo que estaba almacenado en a ; simplemente significa que 2 ahora está almacenado en a lugar. (Y si no había ningún objeto almacenado en 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 tipeada en la memoria. Si a es un int , eso significa que se trata de 4 bytes en algún lugar que el compilador sabe que debe interpretarse como un int . Entonces, cuando haces a = 2 , cambia lo que está almacenado en esos 4 bytes de memoria de 0, 0, 0, 1 a 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 1 y otro para el número 2 . Y a no son 4 bytes de memoria que se representan como un int , es solo un nombre que apunta al objeto 1 . No tiene sentido que a = 2 para convertir el número 1 en el número 2 (que daría a cualquier programador de Python demasiado poder para cambiar el funcionamiento fundamental del universo); lo que hace en cambio es simplemente olvidar el objeto 1 y apuntar al objeto 2 lugar.

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

  • Llamar a un método que está documentado para mutar, como a.append(b) . (Tenga en cuenta que estos métodos casi siempre devuelven None ). Los tipos inmutables no tienen esos métodos, los tipos mutables usualmente sí.
  • Asignando a una parte del objeto, como a.spam = b a[0] = b . Los tipos inmutables no permiten la asignación a atributos o elementos, los tipos mutables usualmente permiten uno u otro.
  • Algunas veces, se usa una asignación aumentada, como a += b , a veces no. Los tipos mutables generalmente mutan el valor; Los tipos inmutables nunca lo hacen, y te dan una copia (calculan a + b , luego asignan el resultado a a ).

Pero si la asignación no es una mutación, ¿cómo se está asignando a una parte de la mutación del objeto? Ahí es donde se pone complicado. a[0] = b no muta a[0] (de nuevo, a diferencia de C ++), pero mutea a (a diferencia de C ++, excepto indirectamente).

Todo esto es por lo que probablemente sea mejor no tratar de poner la semántica de Python en términos de un lenguaje al que estás acostumbrado, y en cambio aprender la semántica de 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 forma fácil de entender eso es si echas un vistazo a una identificación de objetos.

A continuación, verá una cadena que es inmutable. No puedes cambiar su contenido. Levantará un TypeError si intentas cambiarlo. Además, si asignamos contenido nuevo, se crea un nuevo objeto en lugar de los contenidos que se modifican.

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

Puedes hacer eso 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:


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. establecer tipo: 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 usar la función incorporada id() .

Ejemplos, usando en enteros,

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


Un objeto mutable debe tener al menos un método capaz de mutar el objeto. Por ejemplo, el objeto list tiene el método append , que realmente 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 float no tiene un 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 sea a su derecha, nada más. Nunca cambia o crea objetos. Es una declaración de a qué apunta la variable, desde ahora en adelante.

Cuando haces b = b + 0.1 el = operando vincula la variable 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 vincula la variable a ese objeto. Y nada más pasa

En cualquier caso, el = solo hace el enlace. No cambia ni crea objetos.

Cuando haces a = 1.0 , el = operando no crea el flotante, sino la parte 1.0 de la línea. En realidad, cuando escribes 1.0 , es una abreviatura de float(1.0) una llamada de constructor que devuelve un objeto flotante. (Esa es la razón por la que si escribe 1.0 y presiona enter obtendrá el "echo" 1.0 impreso a continuación; ese es el valor de retorno de la función de constructor que llamó)

Ahora bien, si b es un flotante y se asigna a = b , ambas variables apuntan al mismo objeto, pero en realidad las variables no pueden comunicarse entre sí, porque el objeto es inmutable, y si haces b += 1 , ahora b Señalar un nuevo objeto, y a aún apunta al antiguo y no puede saber a qué b apunta.

pero si c es, digamos, una list , y usted asigna a = c , ahora a y c pueden "comunicar", porque la list es mutable, y si usted hace c.append(''msg'') , entonces simplemente verificando a recibe el mensaje.

(Por cierto, cada objeto tiene un número de identificación único asociado, que puede obtener con id(x) . Por lo tanto, puede verificar si un objeto es el mismo o no verificar si su identificación única ha cambiado).


Una forma de pensar en la diferencia:

Las asignaciones a objetos inmutables en python se pueden considerar como copias profundas, mientras que las asignaciones a objetos mutables son superficiales


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á. 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 entero (tipo inmutable) ha sido reconstruido.

En la declaración, la expresión en RHS dará como resultado el valor 10 y cuando esto se asigna a LHS (x), x se reconstruirá a 10. Así que ahora

x ---------> 10

y ---------> 5