Attribute einer anderen Klasse überwachen?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Kniffte
User
Beiträge: 64
Registriert: Dienstag 27. September 2016, 11:05

Hallo Zusammen,

Wie kann ich in einer übergeordneten Klasse, in der zwei Instanzen einer anderen Klasse erzeugt wurden, die Attribute der beiden Instanzen überwachen? Wenn sich ein Attribut in 'dataset_main_blade' ändert, soll eine Funktion 'match_values()' aufgerufen werden, die dann das Attribut in 'dataset_splitter_blade' auf den gleichen wert setzt.

Code: Alles auswählen

class Wheel:
    def __init__(self):
        self.dataset_main_blade = Dataset()
        self.dataset_splitter_blade = Dataset()

    # if shroud value changed in dataset_main_blade -->
    # set shroud value in dataset_splitter_blade to the same value
    # match_values()

    def match_values(self):
        self.dataset_splitter_blade.shroud_value = self.dataset_main_blade.shroud_value

class Dataset:
    def __init__(self):
        self._shroud_value = 0
        self._hub_value = 0

    @property
    def shroud_value(self):
        return self._shroud_value

    @shroud_value.setter
    def shroud_value(self, value):
        print('previous actions...')
        self._shroud_value = value
        print('shroud value set to', value)

    @property
    def hub_value(self):
        return self._hub_value

    @hub_value.setter
    def hub_value(self, value):
        print('previous actions')
        self._hub_value = value
        print('hub value set to', value)
__deets__
User
Beiträge: 14533
Registriert: Mittwoch 14. Oktober 2015, 14:29

Klingt danach als ob dir reactive programming helfen koennte. Dafuer gibt's diverse Bibliotheken, benutzt habe ich bis dato selbst keine - schreibe eine im Moment fuer GPIOs, das ist aber noch zu frueh um damit etwas machen zu koennen. Aber google mal nach "reactive programming python", da finden sich Dinge.
Kniffte
User
Beiträge: 64
Registriert: Dienstag 27. September 2016, 11:05

Danke für den Hinweis __deets__. Wenn ich es richtig verstanden haben, dann wäre das auf jeden Fall eine Möglichkeit meine Anwendung zu verbessern. Nur fällt es mir grad schwer z.B. RxPY gut genug zu verstehen, dass ich es in meine Anwendung einbringen könnte.
Zwischenzeitlich hab ich noch selbst etwas gebastelt, was ohne zusätzliche Bibliothek auskommen würde.
(Vielleicht ist das ja auch etwas "reactive", da ich mich an Observer Pattern orientiert habe?)

Gibt es in meiner aktuellen Variante Fehler, Probleme oder Mängel, die mir nicht auffallen?

Code: Alles auswählen

class Wheel:
    def __init__(self):
        self._changed_observable = None

        self.dataset_main_blade = Dataset('dataset_main_blade', self)
        self.dataset_splitter_blade = Dataset('dataset_splitter_blade', self)

        self.events = {
            'dataset_main_blade_shroud_value':self.match_shroud_values
        }

    @property
    def changed_observable(self):
        return self._changed_observable

    @changed_observable.setter
    def changed_observable(self, value):
        self._changed_observable = value
        if self._changed_observable in self.events:
            self.events[self._changed_observable]()
        self._changed_observable = None


    def match_shroud_values(self):
        print('match_shroud_values called...')
        self.dataset_splitter_blade.shroud_value = self.dataset_main_blade.shroud_value


class Dataset:
    def __init__(self, instance_name, observer):
        self.instance_name = instance_name
        self.observer = observer

        self._shroud_value = 0
        self._hub_value = 0

    @property
    def shroud_value(self):
        return self._shroud_value

    @shroud_value.setter
    def shroud_value(self, value):
        self._shroud_value = value
        print(self.instance_name, 'shroud value set to', value)
        self.observer.changed_observable = '{}_{}'.format(self.instance_name, 'shroud_value')

    @property
    def hub_value(self):
        return self._hub_value

    @hub_value.setter
    def hub_value(self, value):
        self._hub_value = value
        print(self.instance_name, 'hub value set to', value)
        self.observer.changed_observable = '{}_{}'.format(self.instance_name, 'hub_value')


if __name__ == '__main__':

    cw = Wheel()
    cw.dataset_main_blade.shroud_value = 2
__deets__
User
Beiträge: 14533
Registriert: Mittwoch 14. Oktober 2015, 14:29

Fuer mein Verstaendnis ist reactive Programming weniger explizit. Natuerlich ist das Observer-Pattern eine notwendige Vorraussetzung, ohne solche Arten von Ereignissen geht's nicht.

Aber die Benutzung sieht etwas krepelig aus, sehr viel Boilerplate. Reactive Programming versucht das einzudaemmen. Im Idealfall kombiniert man das noch mit "view-as-a-function" (da gibt's glaube ich noch einen besseren Namen fuer, der mir gerade nicht einfaellt), und dann hat man da eine aufgeraeumtere Implementierung, die sich zB auch nicht implizit auf die Reihenfolge von Ereignissen verlaesst - das ist naemlich eine der grossen Herausforderungen bei Observables.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Kniffte hat geschrieben:Hallo Zusammen,

Wie kann ich in einer übergeordneten Klasse, in der zwei Instanzen einer anderen Klasse erzeugt wurden, die Attribute der beiden Instanzen überwachen? Wenn sich ein Attribut in 'dataset_main_blade' ändert, soll eine Funktion 'match_values()' aufgerufen werden, die dann das Attribut in 'dataset_splitter_blade' auf den gleichen wert setzt.
Dann kann man das so sehen, dass die erzeugene Klasse der parent ist und die erzeugten Instanzen sind die children. Dann brauchen die children noch ein Attribut, nämlich den Parent. Dann können sie auch die match methode des parents aufrufen und wenn sie dabei auch noch ihr self mitgeben, weiß der parent, woher es kommt und kann das dann auch noch beim anderen child setzten oder er braucht es nicht wissen, sondern setzt es dann einfach für beide. Diese set Methode muß aber eine andere sein als die, welche das match des parents aufruft.

Also, nicht der Parent überwacht, sondern die set Methode der children ruft die Methode des parents auf.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Kniffte: Wenn es nicht allzu generisch sein soll, könnte dies vielleicht ein Ansatz sein:

Code: Alles auswählen

class Wheel:
    def __init__(self):
        self.dataset_main_blade = Dataset(supervisor=self)
        self.dataset_splitter_blade = Dataset()
 
    def match_values(self, data):
        self.dataset_splitter_blade.__dict__.update(data)
        
        
class Dataset:
    def __init__(self, supervisor=None):
        self._shroud_value = 0
        self._hub_value = 0
        self.supervisor = supervisor
 
    @property
    def shroud_value(self):
        return self._shroud_value
 
    @shroud_value.setter
    def shroud_value(self, value):
        self._shroud_value = value
        print('shroud value set to', value)
        self._report_supervisor()
 
    @property
    def hub_value(self):
        return self._hub_value
 
    @hub_value.setter
    def hub_value(self, value):
        self._hub_value = value
        print('hub value set to', value)
        self._report_supervisor()
        
    def _report_supervisor(self):
        if self.supervisor:
            self.supervisor.match_values(self.__dict__)
            
    
if __name__ == '__main__':
    cw = Wheel()
    cw.dataset_main_blade.shroud_value = 2
    print(cw.dataset_main_blade.shroud_value)    
    print(cw.dataset_splitter_blade.shroud_value)
Antworten