Observer-Pattern auf die Python-Art

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
buhtz
Beiträge: 1105
Registriert: 04.12.2015 17:54:49
Kontaktdaten:

Observer-Pattern auf die Python-Art

Beitrag von buhtz » 09.01.2018 14:26:39

Zum Thema, wie man das Observer-Pattern in Python implementieren kann gibt es auf StackOverflow bereits etliche Fragen und Antworten. Mir ist klar, dass es dazu keine einzige absolute Lösung gibt. In diesem Thread möchte ich gerne über Varianten diskutieren, die möglichst "pythonic" sind.
Ich selbst bin eigentlich stark von C++ und n bisschen 90er-Java geprägt. Aber ich arbeite bereits lange genug mit Python, um zu wissen, dass hier einiges anders und einfacher laufen kann.

Basierend auf diversen StackOverflow-Antworten habe ich dieses Beispiel konstruiert, in dem nur ein Datenobjekt und ein GUI-Element (simuliert) existiert.

Code: Alles auswählen

# basiert auf https://stackoverflow.com/a/44499893/4865723

class Observable:
    """
        The object that need to be observed. Alternative names are 'Subject'.
        In the most cases it is a data object.
    """
    def __init__(self):
        self._observers = []

    def register_observer(self, callback):
        """
        """
        self._observers.append(callback)

    def _broadcast_observers(self, *args, **kwargs):
        """
        """
        for callback in self._observers:
            callback(*args, **kwargs)


class TheData(Observable):
    """
        Example of a data class just for demonstration.
    """
    def __init__(self, data):
        Observable.__init__(self)
        self._data = data

    @property
    def data(self):
        return self._data

    @data.setter
    def data(self, data):
        self._data = data
        self._broadcast_observers()


class TheGUIElement:
    """
        Example of a gui class (Widget) just for demonstration.
        e. g. it could be a text field in GUI.
    """
    def __init__(self, data):
        self._data = data
        data.register_observer(self._data_updated)
        self._redraw()

    def _redraw(self):
        print('in _redraw(): ' + data.data)

    def _data_updated(self, **kwargs):
        """
            This is the callback that is called by the Observable if the
            data changed.
        """
        print('in _data_updated() - kwargs: {}'.format(kwargs))
        self._redraw()

if __name__ == '__main__':
    data = TheData('DATA')
    gui = TheGUIElement(data)

    data.data = 'SECOND DATA'
In einem Kommentar auf StackOverflow wird noch die Möglichkeit eines Dekorators angemerkt. Davon habe ich aber keine konkrete Vorstellung.
Debian 11 & 12; Desktop-PC, Headless-NAS, Raspberry Pi 4
Teil des Upstream Betreuer Teams von Back In Time (Debianbackintime)

buhtz
Beiträge: 1105
Registriert: 04.12.2015 17:54:49
Kontaktdaten:

Re: Observer-Pattern auf die Python-Art

Beitrag von buhtz » 19.01.2018 09:12:11

Hat niemand einen Hinweis hierzu? Mir ist nicht klar, wo ich hier noch einen Dekorator anbringen könnte.
Debian 11 & 12; Desktop-PC, Headless-NAS, Raspberry Pi 4
Teil des Upstream Betreuer Teams von Back In Time (Debianbackintime)

Antworten