Pregunta

código :

a = {...} # a is an dict with arbitrary contents
b = a.copy()
  1. ¿Qué papel juega la mutabilidad de las claves y los valores de los dicts?
  2. ¿Cómo me aseguro cambios en las claves o valores de un dict no se reflejan en el otro?
  3. ¿Cómo se relaciona esto con la hashable limitación de la llaves dict?
  4. ¿Hay diferencias de comportamiento entre Python 2.x y 3.x Python?

¿Cómo puedo comprobar si un tipo es mutable en Python?

¿Fue útil?

Solución

1) Las llaves no debe ser mutable, menos tiene una clase definida por el usuario que es hashable sino también mutable. Eso es todo lo que se ve obligado a usted. No obstante, el uso de un hashable, objeto mutable como una clave dict podría ser una mala idea.

2) Al no compartir los valores entre los dos dicts. Está bien compartir las claves, ya que deben ser inmutables. Copiar el diccionario, en el sentido módulo copy, es definitivamente seguro. Llamando al constructor dict aquí trabaja, también: b = dict(a). También es posible usar los valores inmutables.

3) Todos los tipos predefinidos son inmutables hashable. Todos los tipos incorporados no son mutables hashable. Para que un objeto sea hashable, debe tener el mismo hash largo de toda su vida, incluso si está mutado.

4) No es que sea consciente de; Estoy describiendo 2.x.

Un tipo es mutable si no es inmutable. Un tipo es inmutable, si se trata de un tipo incorporado inmutable: str, int, long, bool, float, tuple, y probablemente un par más que me olvido. Los tipos definidos por el usuario son siempre mutable.

Un objeto es mutable si no es inmutable. Un objeto es inmutable si consiste, de forma recursiva, de sub-objetos sólo inmutables-mecanografiadas. Por lo tanto, una tupla de listas es mutable; no puede sustituir a los elementos de la tupla, pero se puede modificar a través de la interfaz de la lista, el cambio de los datos en general.

Otros consejos

En realidad no hay tal cosa como la mutabilidad o inmutabilidad en el nivel de idioma en Python. Algunos objetos no proporcionan ninguna manera de cambiarlos (por ejemplo, cadenas y las tuplas.), Y también lo son efectivamente inmutable, pero es puramente conceptual; No hay propiedad a nivel de lenguaje que indica esto, ni a su código Python ni a sí mismo.

La inmutabilidad no es realmente relevante para dicts; es perfectamente posible utilizar valores mutables como claves. Lo que importa es la comparación y el hash: el objeto debe permanecer siempre igual a sí mismo. Por ejemplo:

class example(object):
    def __init__(self, a):
        self.value = a
    def __eq__(self, rhs):
        return self.value == rhs.value
    def __hash__(self):
        return hash(self.value)

a = example(1)
d = {a: "first"}
a.data = 2
print d[example(1)]

A continuación, example es no inmutable; estamos modificando con a.data = 2. Sin embargo, lo estamos utilizando como clave de un hash sin ningún problema. ¿Por qué? La propiedad que estamos cambiando no tiene ningún efecto en la igualdad:. El hash no se ha modificado, y example(1) es siempre igual a example(1), haciendo caso omiso de cualquier otra propiedad

El uso más común de esto es el almacenamiento en caché y memoization:. Que tenga una propiedad en caché o no no cambia lógicamente el objeto, y por lo general no tiene efecto sobre la igualdad

(voy a parar aquí -. Por favor no pregunte cinco preguntas a la vez)

Hay MutableSequence, MutableSet, MutableMapping en el módulo colecciones . Que se puede utilizar para comprobar la mutabilidad de tipos de prefabricados.

issubclass(TYPE, (MutableSequence, MutableSet, MutableMapping))

Si desea utilizar esto en tipos definidos por el usuario, el tipo debe ser heredado, ya sea de uno de ellos o registrado como una subclase virtual.

class x(MutableSequence):
    ...

o

class x:
    ...

abc.ABCMeta.register(MutableSequence,x)

Realmente no hay Garantía que un tipo que es hashable también es inmutable, pero al menos, la correcta aplicación de __hash__ requiere que el tipo es inmutable, con respecto a su propio hachís, y para la igualdad. Esto no se aplica de una manera determinada.

Sin embargo, todos somos adultos. No sería prudente para implementar __hash__ a menos que realmente en serio. En términos generales, esto sólo equivale a decir que si un tipo realmente puede ser utilizado como una clave de diccionario, entonces está destinado a ser utilizado de esa manera.

Si usted está buscando algo que es como un diccionario, sino también inmutable, a continuación, namedtuple podría ser su mejor apuesta de lo que hay en la biblioteca estándar. Es cierto que no es una aproximación muy buena, pero es un comienzo.

  1. dict teclas debe ser hashable, lo que implica que tienen un de hash de valor inmutable. dict valores puede o no puede ser mutable; Sin embargo, si son mutables esto afecta a su segunda pregunta.

  2. "Los cambios en las teclas" no se reflejará entre los dos dicts. Los cambios en los valores inmutables, tales como cadenas tampoco serán reflejadas. Los cambios en los objetos mutables, como las clases definidas por el usuario se reflejarán porque el objeto se almacena por ID (es decir, de referencia).

    class T(object):
      def __init__(self, v):
        self.v = v
    
    
    t1 = T(5)
    
    
    d1 = {'a': t1}
    d2 = d1.copy()
    
    
    d2['a'].v = 7
    d1['a'].v   # = 7
    
    
    d2['a'] = T(2)
    d2['a'].v   # = 2
    d1['a'].v   # = 7
    
    
    import copy
    d3 = copy.deepcopy(d2) # perform a "deep copy"
    d3['a'].v = 12
    d3['a'].v   # = 12
    d2['a'].v   # = 2
    
  3. Creo que esto se explica por las dos primeras respuestas.

  4. No, que yo sepa en este sentido.

algunos pensamientos adicionales

Hay dos cosas principales que debe saber para entender el comportamiento de los teclas : Las claves deben ser hashable (lo que significa que implementan object.__hash__(self) ) y también deben ser "comparable" (lo que significa que implementar algo así como object.__cmp__(self) ). Una importante para llevar a partir de los documentos: por defecto, las funciones hash objetos definidos por el usuario retorno id() .

Considere este ejemplo:

class K(object):
  def __init__(self, x, y):
     self.x = x
     self.y = y
  def __hash__(self):
     return self.x + self.y

k1 = K(1, 2)
d1 = {k1: 3}
d1[k1] # outputs 3
k1.x = 5
d1[k1] # KeyError!  The key's hash has changed!
k2 = K(2, 1)
d1[k2] # KeyError!  The key's hash is right, but the keys aren't equal.
k1.x = 1
d1[k1] # outputs 3

class NewK(object):
  def __init__(self, x, y):
     self.x = x
     self.y = y
  def __hash__(self):
     return self.x + self.y
  def __cmp__(self, other):
     return self.x - other.x

nk1 = NewK(3, 4)
nd1 = {nk1: 5}
nd1[nk1] # outputs 5
nk2 = NewK(3, 7)
nk1 == nk2 # True!
nd1[nk2] # KeyError! The keys' hashes differ.
hash(nk1) == hash(nk2) # False
nk2.y = 4
nd1[nk2] # outputs 5

# Where this can cause issues:
nd1.keys()[0].x = 5
nd1[nk1] # KeyError! nk1 is no longer in the dict!
id(nd1.keys()[0]) == id(nk1)  # Yikes. True?!
nd1.keys()[0].x = 3
nd1[nk1]  # outputs 5
id(nd1.keys()[0]) == id(nk1)  # True!

Valores son mucho más fáciles de entender, las tiendas dict referencias a objetos. Lea las secciones sobre hashable. Cosas como las cadenas son inmutables, si el "cambio" de ellos, el dict la ha cambiado ahora hace referencia a un nuevo objeto. Los objetos que son mutables pueden ser "cambiados en el lugar", de ahí el valor de ambos dicts va a cambiar.

d1 = {1: 'a'}
d2 = d1.copy()
id(d1[1]) == id(d2[1]) # True
d2[1] = 'z'
id(d1[1]) == id(d2[1]) # False

# the examples in section 2 above have more examples of this.

De todos modos, aquí están los puntos principales de todo esto:

  • En teclas , puede que no sea mutabilidad , sino hashability y comparabilidad , que se preocupa.
  • Usted se preocupa por la mutabilidad de los valores, porque, por definición, el valor de un objeto mutable se puede cambiar sin cambiar la referencia a la misma.

No creo que hay una manera general a la prueba de cualquiera de esos puntos. Las pruebas de idoneidad dependerían en su caso de uso. Por ejemplo, puede ser suficiente para comprobar que un objeto hace o no implementa funciones __hash__ y la comparación (__eq__ o __cmp__). Al igual que en cuanto a, usted podría ser capaz de "verificación" método __setattr__ de un objeto de alguna forma de determinar si es mutable.

Dicts son conjuntos no ordenados de clave: pares de valores. Las claves deben ser inmutable, y por lo tanto hashable. Para determinar si un objeto es hashable, puede utilizar la función hash():

>>> hash(1)
1
>>> hash('a')
12416037344
>>> hash([1,2,3])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash((1,2,3))
2528502973977326415
>>> hash({1: 1})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'

Los valores, por otra parte, puede ser cualquier objeto. Si es necesario comprobar si un objeto es inmutable, entonces me gustaría utilizar hash().

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top