Formas de hacer una clase inmutable en Python.

Estoy haciendo un poco de computación distribuida en la que varias máquinas se comunican bajo el supuesto de que todas tienen versiones idénticas de varias clases. Por lo tanto, parece ser un buen diseño para hacer estas clases inmutables; no en el sentido de que debe frustrar a un usuario con malas intenciones, solo lo suficientemente inmutable para que nunca sea modificado por accidente.

¿Cómo voy a hacer esto? Por ejemplo, ¿cómo implementaría una metaclase que hace que la clase que la usa sea inmutable después de su definición?

>>> class A(object): ... __metaclass__ = ImmutableMetaclass >>> A.something = SomethingElse # Don't want this >>> a = A() >>> a.something = Whatever # obviously, this is still perfectly fine. 

Los métodos alternativos también están bien, como un decorador / función que toma una clase y devuelve una clase inmutable.

Si el viejo truco de usar __slots__ no se ajusta a usted, esto o alguna variante de eso puede hacerlo: simplemente escriba el método __setattr__ de su metaclase para que sea su guardia. En este ejemplo, evito que se asignen nuevos atributos, pero permito la modificación de los existentes:

 def immutable_meta(name, bases, dct): class Meta(type): def __init__(cls, name, bases, dct): type.__setattr__(cls,"attr",set(dct.keys())) type.__init__(cls, name, bases, dct) def __setattr__(cls, attr, value): if attr not in cls.attr: raise AttributeError ("Cannot assign attributes to this class") return type.__setattr__(cls, attr, value) return Meta(name, bases, dct) class A: __metaclass__ = immutable_meta b = "test" a = A() ac = 10 # this works Ac = 20 # raises valueError 

No pierdas el tiempo en clases inmutables.

Hay cosas que puedes hacer que son mucho más simples que perder el tiempo intentando crear un objeto inmutable.

Aquí hay cinco técnicas separadas. Puedes elegir y elegir entre ellos. Cualquiera trabajará. Algunas combinaciones funcionarán, también.

  1. Documentación. En realidad, no olvidarán esto. Dales crédito.

  2. Prueba de unidad. Simule los objetos de su aplicación con un simulacro simple que maneja __setattr__ como una excepción. Cualquier cambio en el estado del objeto es un fallo en la prueba de la unidad. Es fácil y no requiere ninguna progtwigción elaborada.

  3. Reemplace __setattr__ para generar una excepción en cada bash de escritura.

  4. collections.namedtuple . Son inmutables fuera de la caja.

  5. collections.Mapping . Es inmutable, pero necesitas implementar algunos métodos para que funcione.

Si no te importa reutilizar el trabajo de otra persona:

http://packages.python.org/pysistence/

Estructuras de datos persistentes inmutables (en el sentido funcional, no de escritura a escritorio).

Incluso si no los usa tal como están, el código fuente debería proporcionar alguna inspiración. Su clase expando, por ejemplo, toma un objeto en su constructor y devuelve una versión inmutable de él.