tutorial sintaxis org guide book python nested immutability hashable

sintaxis - python guide



¿Cómo probar la "inmutabilidad en cualquier profundidad" en Python? (4)

Estoy definiendo un objeto de Python como "inmutable a cualquier profundidad" iff

  1. es (nominalmente) inmutable; y
  2. si es un objeto "contenedor", entonces contiene solo objetos que son "inmutables a cualquier profundidad";

Por ejemplo ((1, 2), (3, 4)) es inmutable a cualquier profundidad, mientras que ((1, 2), [3, 4]) no lo es (aunque este último, en virtud de ser una tupla) , es "nominalmente" inmutable).

¿Hay alguna manera razonable de probar si un objeto de Python es "inmutable a cualquier profundidad"?

Es relativamente fácil probar la primera condición (por ejemplo, usar collections.Hashable Clase __hash__ y descuidar la posibilidad de un método __hash__ implementado incorrectamente), pero la segunda condición es más difícil de probar, debido a la heterogeneidad de los objetos "contenedores". y los medios de iterar sobre sus "contenidos" ...

¡Gracias!


Imagino que estás buscando algo como esto:

def deeply_hashable(obj): try: hash(obj) except TypeError: return False try: iter(obj) except TypeError: return True return all(deeply_hashable(o) for o in obj)

Un problema obvio aquí es que iterar sobre un dict itera sobre sus claves, que son siempre inmutables, en lugar de sus valores, que es lo que le interesa. No hay una forma fácil de evitar esto, aparte, por supuesto, del dict - que no ayuda con otras clases que pueden comportarse de manera similar, pero no se derivan de dict Al final, estoy de acuerdo con delnan: no hay una manera simple, elegante y general de hacer esto.


No estoy seguro de lo que estás buscando exactamente. Pero usando sus datos de ejemplo:

>>> a = ((1, 2), (3, 4)) >>> b = ((1, 2), [3, 4]) >>> isinstance(a, collections.Hashable) True >>> isinstance(b, collections.Hashable) True

Por lo tanto, de hecho el uso de collections.Hashable no es el camino a seguir. Sin embargo,

>>> hash(a) 5879964472677921951 >>> hash(b) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unhashable type: ''list''

Por lo tanto, al menos para los datos de ejemplo, usar hash es suficiente para verificar si el objeto es manejable. Por supuesto, como ya ha señalado en su pregunta, si __hash__ está implementado incorrectamente para una subclase de, digamos, una list , entonces esta verificación no funcionará.


No hay pruebas generales de inmutabilidad. Un objeto es inmutable solo si ninguno de sus métodos puede mutar los datos subyacentes.

Lo más probable es que esté interesado en la capacidad de uso, que generalmente depende de la inmutabilidad. Los contenedores que son hashable recursivamente picará sus contenidos (es decir, tuplas y conjuntos congelados). Por lo tanto, su prueba equivale a ejecutar hash(obj) y si tiene éxito, entonces fue muy fácil de manejar.

IOW, tu código ya usó la mejor prueba disponible:

>>> a = ((1, 2), (3, 4)) >>> b = ((1, 2), [3, 4]) >>> hash(a) 5879964472677921951 >>> hash(b) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unhashable type: ''list''


¡Tiene sentido tener tal prueba!

¡Considere el momento de ''deepcopy () - ing'' (o clone manualmente () manualmente un objeto frente a una simple asignación de referencia!

Imagine que dos entidades necesitan tener un mismo objeto, pero confíe en que no se cambia (las dict-keys son un buen ejemplo).

Entonces, solo es seguro usar una asignación de referencia, si y solo si se puede verificar la inmutabilidad.

Consideraría probar recursivamente para algo como

def check(Candidate): if isinstance(Candidate, (str, int, long)): return True elif isinstance(Candidate, tuple): return not any(not check(x) for x in Candidate) else: return False