20 Stimmen

Wie man eine Klasse in Python unveränderlich macht

Ich beschäftige mich mit verteiltem Rechnen, bei dem mehrere Maschinen unter der Annahme kommunizieren, dass sie alle identische Versionen verschiedener Klassen haben. Daher scheint es ein gutes Design zu sein, diese Klassen unveränderlich zu machen; nicht in dem Sinne, dass es einen Benutzer mit schlechten Absichten vereiteln muss, nur unveränderlich genug, dass es nie versehentlich geändert wird.

Wie würde ich vorgehen? Wie würde ich zum Beispiel eine Metaklasse implementieren, die die Klasse, die sie verwendet, nach ihrer Definition unveränderlich macht?

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

Alternative Methoden sind auch in Ordnung, wie z.B. ein Dekorator/Funktion, die eine Klasse annimmt und eine unveränderliche Klasse zurückgibt.

10voto

jsbueno Punkte 84804

Wenn der alte Trick mit der __slots__ nicht passt, kann dies, oder eine Variante davon, ausreichen: Schreiben Sie einfach die __setattr__ Methode Ihrer Metaklasse zu Ihrem Wächter zu machen. In diesem Beispiel verhindere ich, dass neue Attribute zugewiesen werden, erlaube aber die Änderung bestehender Attribute:

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()
a.c = 10 # this works
A.c = 20 # raises valueError

7voto

S.Lott Punkte 371691

Verschwenden Sie keine Zeit mit unveränderlichen Klassen.

Es gibt Dinge, die man tun kann, die viel, viel einfacher sind, als sich mit dem Versuch herumzuschlagen, ein unveränderliches Objekt zu erstellen.

Hier sind fünf verschiedene Techniken. Sie können unter ihnen auswählen. Jede einzelne wird funktionieren. Auch einige Kombinationen sind möglich.

  1. Dokumentation. Das werden sie auch nicht vergessen. Geben Sie ihnen Anerkennung.

  2. Einheitstest. Mocken Sie Ihre Anwendungsobjekte mit einem einfachen Mock, der Folgendes behandelt __setattr__ als eine Ausnahme. Jede Zustandsänderung des Objekts führt zu einem Fehlschlag im Einheitstest. Es ist einfach und erfordert keine aufwendige Programmierung.

  3. Überschreiben Sie __setattr__ bei jedem Schreibversuch eine Ausnahme auslösen.

  4. collections.namedtuple . Sie sind von Haus aus unveränderlich.

  5. collections.Mapping . Sie ist unveränderlich, aber Sie müssen ein paar Methoden implementieren, damit sie funktioniert.

1voto

mavnn Punkte 8433

Wenn es Ihnen nichts ausmacht, die Arbeit eines anderen wiederzuverwenden:

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

Unveränderliche persistente Datenstrukturen (im funktionalen Sinne, nicht im Sinne von "write to desk").

Selbst wenn Sie sie nicht so verwenden, wie sie sind, sollte der Quellcode einige Anregungen liefern. Die Klasse expando zum Beispiel nimmt ein Objekt in ihrem Konstruktor auf und gibt eine unveränderliche Version davon zurück.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X