Suche…


Einfacher Deskriptor

Es gibt zwei verschiedene Arten von Deskriptoren. __get__() werden als Objekte definiert, die sowohl eine __get__() als auch eine __set__() -Methode definieren, wohingegen Nicht-Deskriptoren nur eine __get__() -Methode definieren. Diese Unterscheidung ist wichtig, wenn Sie Überschreibungen und den Namensraum des Wörterbuchs einer Instanz in Betracht ziehen. Wenn ein Datendeskriptor und ein Eintrag im Wörterbuch einer Instanz denselben Namen haben, hat der Datendeskriptor Vorrang. Wenn jedoch ein Nicht-Daten-Deskriptor und ein Eintrag im Wörterbuch einer Instanz denselben Namen haben, hat der Eintrag des Instanzwörterbuchs Vorrang.

Um einen schreibgeschützten Datendeskriptor zu erstellen, definieren Sie sowohl get () als auch set (), wobei set () beim Aufruf einen AttributeError auslöst. Das Definieren der set () - Methode mit einem Platzhalter für die Ausnahmebereitstellung reicht aus, um sie zu einem Datendeskriptor zu machen.

descr.__get__(self, obj, type=None) --> value
descr.__set__(self, obj, value) --> None
descr.__delete__(self, obj) --> None

Ein umgesetztes Beispiel:

class DescPrinter(object):
    """A data descriptor that logs activity."""
    _val = 7
    
    def __get__(self, obj, objtype=None):
        print('Getting ...')
        return self._val

    def __set__(self, obj, val):
        print('Setting', val)
        self._val = val
    
    def __delete__(self, obj):
        print('Deleting ...')
        del self._val


class Foo():
    x = DescPrinter()       

i = Foo()
i.x
# Getting ...
# 7

i.x = 100
# Setting 100
i.x
# Getting ...
# 100

del i.x
# Deleting ...
i.x
# Getting ...
# 7

Zwei-Wege-Konvertierungen

Beschreibungsobjekte können dazu führen, dass verwandte Objektattribute automatisch auf Änderungen reagieren.

Angenommen, wir möchten einen Oszillator mit einer bestimmten Frequenz (in Hertz) und einer Periode (in Sekunden) modellieren. Wenn wir die Frequenz aktualisieren, möchten wir, dass die Periode aktualisiert wird, und wenn wir die Periode aktualisieren, möchten wir, dass die Frequenz aktualisiert wird:

 >>> oscillator = Oscillator(freq=100.0)  # Set frequency to 100.0 Hz
>>> oscillator.period  # Period is 1 / frequency, i.e. 0.01 seconds
0.01
>>> oscillator.period = 0.02  # Set period to 0.02 seconds
>>> oscillator.freq # The frequency is automatically adjusted
50.0
>>> oscillator.freq = 200.0  # Set the frequency to 200.0 Hz
>>> oscillator.period  # The period is automatically adjusted
0.005

Wir wählen einen der Werte (Frequenz in Hertz) als "Anker", dh den Wert, der ohne Konvertierung eingestellt werden kann, und schreiben eine Deskriptorklasse dafür:

class Hertz(object):
    def __get__(self, instance, owner):
        return self.value

    def __set__(self, instance, value):
        self.value = float(value)

Der "andere" Wert (Zeitraum in Sekunden) wird in Bezug auf den Anker definiert. Wir schreiben eine Deskriptorklasse, die unsere Konvertierungen durchführt:

class Second(object):
    def __get__(self, instance, owner):
        # When reading period, convert from frequency
        return 1 / instance.freq
    
    def __set__(self, instance, value):
        # When setting period, update the frequency
        instance.freq = 1 / float(value)

Jetzt können wir die Oszillator-Klasse schreiben:

class Oscillator(object):
    period = Second()  # Set the other value as a class attribute

    def __init__(self, freq):
        self.freq = Hertz()  # Set the anchor value as an instance attribute
        self.freq = freq  # Assign the passed value - self.period will be adjusted


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow