Interaktion zwischen zwei Skripten?

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
Scholastik
User
Beiträge: 53
Registriert: Freitag 7. Juli 2017, 12:35

Hallo zusammen,

wie können zwei Skripte miteinander kommunizieren?

Also jedes Skript hat eine Klasse, die nach Start in Dauerschleife ihre eigenen Aufgaben ausführt. So gesehen könnte man sie getrennt laufen lassen.
Aber die beiden Skripte sollen Einfluss aufeinander nehmen können. Zb. den Wert einer self Variablen des anderen Skripts abfragen oder evlt sogar ändern können.

Einfachste Lösung wäre sicherlich alles in dasselbe Skript zu verschieben, dann sollten die Klassen ja aufeinander zugreifen können, oder?
Aber wenn ich der Übersicht halber nun 2 Skripte möchte, wie geht das dann?

Wenn ich in Skript A das Skript B importiere, dann funktioniert der Zugriff nur in eine Richtung, nicht in beide, oder?
Benutzeravatar
pixewakb
User
Beiträge: 1409
Registriert: Sonntag 24. April 2011, 19:43

Beide Module (?) in ein Skript importieren und dort z. B. in Dauerschleife laufen lassen.

Nur mal laut gedacht - obige Lösung ist m. E. die allein glücklich machende:
Wenn beide Skripte auf das identische Datenmaterial zugreifen, dann kann man halt einem Skript sagen, dass es auf ein Ereignis warten soll oder regelmäßig prüfen soll, ob neue Daten hinzugekommen sind.

PS: Ein Skript mit einer Klasse klingt nach Java und nicht nach Modulen in Python.
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

@Scholastik: Übersichtlichkeit kann man durch strukturierte Programmierung erreichen, z.B. in dem man verschiedene Aufgaben in unterschiedliche Module packt. Wenn aber beide Klassen voneinander abhängen, hast Du de facto keine getrennten Module. Um aber eine qualifizierte Antwort geben zu können, brauchen wir mehr Informationen, was Du konkret versuchst zu erreichen.
Scholastik
User
Beiträge: 53
Registriert: Freitag 7. Juli 2017, 12:35

Danke.

Ich stelle mir das ganze so vor, dass beides parallel läuft, also zb das eine ist eine websocket verbindung:

Code: Alles auswählen

import pusherclient #live stream client: https://github.com/ekulyk/PythonPusherClient
import time

class pusher_ws:
    def __init__(self):
        self.datas = []

    def runner(self):
        self.pusher = pusherclient.Pusher("abcdef")
        self.pusher.connection.bind('pusher:connection_established', self.connect_handler)
        self.pusher.connect()

    def connect_handler(self,data): 
        xy_channel = self.pusher.subscribe("xy")
        xy_channel.bind('xy', self.xy_callback)

    def xy_callback(self,data):
        self.datas.append(data) # make something with data
        if Haupt.counter > 10:
            self.datas = []
            Haupt.counter = 0
    

class Hauptskript:
    def __init__(self):
        self.counter = 0
        
    def starten(self):
        WS.runner()
        while True:
            self.counter += 1
            time.sleep(1) # do something
            if self.counter > 10:
                WS.datas = [] # delete datas from ws
                self.counter = 0
                
if __name__ == '__main__':
    WS = pusher_ws()
    Haupt = Hauptskript()
    Haupt.starten()
Es werden beide Klassen imselben Skript (Skript==eine .py Datei) gestartet. Deswegen denke ich, dass nun beide Klassen durch Verwendung der Globalen Variable aufeinander zugreifen können.
Wenn ich nun aber die "class pusher_ws" in einem eigenen Skript hätte und importiere, wird die Abfrage nach "Haupt.counter" im pusher skript einen Fehler produzieren.

Wie erreiche ich also dasselbe Ergebnis, als wenn ich beide mithilfe der globalen Variable imselben Skript verbinde?
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das erreichst du, indem du in deinem Fall die geteilte Datenstruktur an beide Instanzen uebergibst, statt ueber globale Variablen zu arbeiten.

Code: Alles auswählen

class Pusher(object):

     def __init__(self, queue):
           self._queue = queue


class WasAnderes(object):

      def __init__(self, queue):
            self._queue = queue


def main():
      q = Queue.Queue()
      pusher = Pusher(q)
      was_anderes = WasAnderes(q)
Scholastik
User
Beiträge: 53
Registriert: Freitag 7. Juli 2017, 12:35

__deets__ hat geschrieben:Das erreichst du, indem du in deinem Fall die geteilte Datenstruktur an beide Instanzen uebergibst, statt ueber globale Variablen zu arbeiten.
Danke :)

Ich habe deinen Lösungsvorschlag nun so verstanden, dass ich immer, wenn ich interagieren will, mit put() etwas an queue übergebe, und mit get() dies dann im anderen skript abrufen kann?

Und zwar würde ich es so machen:
- Wenn counter>10 würde ich queue.put("reset") machen und counter 0 setzen.
- im callback des pushers mache ich queue.get(False) um zu sehen, ob was in der queue ist. wenn nicht dann weiter, wenn doch und es "reset" string ist, dann datas löschen.

Allerdings scheint mir das doch eine ziemlich umständliche Lösung zu sein, die besonders unübersichtlich wird, wenn ich neben dem "reset" befehl noch 100 andere Befehle übergeben wollen würde und weitere pusher callbacks hätte. Dann macht das ganze queue System doch eig keinen Sinn mehr, weil sie ja garnicht zwingend in einer Reihenfolge abgearbeitet werden müssen.

Aber ich glaub der wichtige Ansatz den du mir mitteilen wolltest, ist ein geteiltes/gemeinsames Objekt zu übergeben.
Vielleicht anstelle von queue zb. einfach ein Dictionary übergeben, in dem veränderte Werte dann in beiden Skripten bekannt werden?
Sollte funktionieren, aber ist das auch sinnvoll? Zb. im Bezug darauf, wenn im einem Skript zb. gerade über das dictionary iteriert wird, während es vom anderen skript geändert wird
BlackJack

@Scholastik: Genau wegen solcher Probleme nimmt man eine Queue. Die ist „threadsicher“ und man hat eine Reihenfolge damit nichts durcheinander geht. Wenn Du da mehr Freiheiten möchtest, musst Du Dich auch selbst um die Probleme kümmern (Sperrmechanismen aus `threading`) und dann sollte das nach Möglichkeit auch mehr Parallelität bieten als die Queue, denn sonst hätte man Arbeit in etwas gesteckt und mehr Fehler riskiert, als wenn man gleich eine Queue verwendet hätte.
Scholastik
User
Beiträge: 53
Registriert: Freitag 7. Juli 2017, 12:35

BlackJack hat geschrieben:@Scholastik: Genau wegen solcher Probleme nimmt man eine Queue. Die ist „threadsicher“ und man hat eine Reihenfolge damit nichts durcheinander geht. Wenn Du da mehr Freiheiten möchtest, musst Du Dich auch selbst um die Probleme kümmern (Sperrmechanismen aus `threading`) und dann sollte das nach Möglichkeit auch mehr Parallelität bieten als die Queue, denn sonst hätte man Arbeit in etwas gesteckt und mehr Fehler riskiert, als wenn man gleich eine Queue verwendet hätte.
Das dictionray könnte ungefähr so aussehen:
Befehlsdict = {"counterreset":False,"xyreset":False,"AktuelleDatas":[5,6,7],"AndereInformationen":{"abc":1,"cdf":[2,3,4,5]}}

Anstatt jeden einzelnen eintrag ala queue.put("counterreset") zu übergeben, könnte ich vermutlich auch einfach das komplette Befehlsdict durch queue übergeben, oder? Das war mir vorher nicht ganz klar :) Dann könnte es wiederum also doch gut funktionieren.

Werde versuchen es umzusetzen und wenn dabei Probleme auftreten, meld ich mich nochmal :-)

Danke.

PS:
doch noch ne kurze Frage:
Wenn ich ein dictionary über queue übergebe, ist es dann eine deepcopy oder ist es nur ein Verweis? Damits fehlerfrei läuft (wenn das dictionary so wie oben aussieht), sollte man ja eine vollständige Kopie verwenden, deswegen frag ich. Also lieber eine deepcopy des dictionaries an queue übergeben? Ja, oder?

edit:
Das Haupskript übergibt das dictionary nun mit queue.put . Im pusher skript möchte ich aber immer nur das aktuellste dictionary haben. Wie setze ich das um? Also in dem Fall, dass es häufiger im hauptskript aktualsiert wird, als es das pusher skript abruft. Dann würden sich ja zb 11 einträge in queue befinden, von denen ich nur eines brauche. Selbst mit LiFO würde queue dadurch unnötig groß. Also jedesmals wenn bevor ich put() mache, alles in queue löschen?? Das klingt verkehrt.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Scholastik hat geschrieben:Das Haupskript übergibt das dictionary nun mit queue.put . Im pusher skript möchte ich aber immer nur das aktuellste dictionary haben. Wie setze ich das um? Also in dem Fall, dass es häufiger im hauptskript aktualsiert wird, als es das pusher skript abruft. Dann würden sich ja zb 11 einträge in queue befinden, von denen ich nur eines brauche. Selbst mit LiFO würde queue dadurch unnötig groß. Also jedesmals wenn bevor ich put() mache, alles in queue löschen?? Das klingt verkehrt.
Darauf wurde weiter oben schon kurz eingegangen. Um das entscheiden zu können, müsstest du das geplante Verhalten deines Programms etwas genauer festlegen, bzw. darstellen wie die beiden Module miteinander interagieren. Soll das empfangende Modul sich einfach nur den aktuellen Wert schnappen und damit rechnen, oder soll dessen Berechnung erst angestoßen werden, wenn tatsächlich auch ein neuer Wert da ist (und dabei ggf. alle älteren Werte ignoriert)?
Das Leben ist wie ein Tennisball.
Scholastik
User
Beiträge: 53
Registriert: Freitag 7. Juli 2017, 12:35

EyDu hat geschrieben:
Scholastik hat geschrieben:Das Haupskript übergibt das dictionary nun mit queue.put . Im pusher skript möchte ich aber immer nur das aktuellste dictionary haben. Wie setze ich das um? Also in dem Fall, dass es häufiger im hauptskript aktualsiert wird, als es das pusher skript abruft. Dann würden sich ja zb 11 einträge in queue befinden, von denen ich nur eines brauche. Selbst mit LiFO würde queue dadurch unnötig groß. Also jedesmals wenn bevor ich put() mache, alles in queue löschen?? Das klingt verkehrt.
Darauf wurde weiter oben schon kurz eingegangen. Um das entscheiden zu können, müsstest du das geplante Verhalten deines Programms etwas genauer festlegen, bzw. darstellen wie die beiden Module miteinander interagieren. Soll das empfangende Modul sich einfach nur den aktuellen Wert schnappen und damit rechnen, oder soll dessen Berechnung erst angestoßen werden, wenn tatsächlich auch ein neuer Wert da ist (und dabei ggf. alle älteren Werte ignoriert)?
Es soll schon so wie im ersten code beispiel laufen.
Also beides läuft unabhängig voneinander, aber beides Zugriff auf ein aktuelles gemeinsames dictionary haben (im ersten code symbolisiert durch self.counter).
Um deine Frage also direkt zu beantworten, soll eine ständig wiederholt aufgerufene Funktion sich den aktuellsten Wert schnappen.
Antworten