zyklische Funktionsdurchführung mit vorgebenener Frequenz ohne globale Variable - wie geht das?

  • Hallo zusammen,

    in einem kleinen Steuerprogramm muss ich mit bestimmter Frequenz (z.B. 10 oder 50Hz) immer wieder Daten senden.

    Das wird in einer Funktion gemacht. Im Grunde krieg ich das hin, indem ich die Zeitdifferenz zwischen time.time() und einem Initialwert (STARTZEIT) prüfe.

    Zur Verdeutlichung hab ich nen kleinen Code unten angefügt, der den Kern meines Anliegens beinhaltet.

    Das Problem ist, dass beim Aufruf der Funktion der Wert von STARTZEIT irgendwoher kommen muss und ich das nur hinbekomme, wenn ich den Wert in einer globalen Variable führe. Zwischen zwei Aufrufen der Funktion muss der Wert halt irgendwo gespeichert bleiben. In sofern funktioniert es nicht, dass der Wert erst in der Funktion jedesmal neu initialisiert wird.

    Meine Frage ist: gibt es einen besseren Weg, dies zu tun? Globale Variablen soll man ja möglichst vermeiden und ich möchte gerne herausfinden, wie das ein Profi machen würde.

    Natürlich kann man den Wert (STARTZEIT) auch immer wieder über lokale Variablen an die Funktion übergeben und den (ggf) neuen Wert über return(STARTZEIT) rausholen. Allerdings sagt mir mein Bauchgefühl, das geht bestimmt eleganter, nur reichen meine Python-Skills (noch) nicht so weit. Über diesen Punkt komme ich im Moment irgendwie nicht hinweg.

    Das mit Objektorientierung hab ich noch nicht so ganz geschnallt aber wenn das der bessere Weg ist, wäre ich für ein paar Hinweise dankbar...

    Ich hoffe, ich konnte mein Problem verständlich beschreiben ::)


  • Die saubere Loesung ist ganz klar eine Klasse.


    Weniger sauber, aber dem Wissenstand angepasst:


    Einmal editiert, zuletzt von Tell ()

  • Hallo,


    also das die Funktion einen Wert `startzeit` zurück liefert ist IMHO von der Nomeklatur verwirrend. Korrekter wäre `zeit_der_letzten_ausfuehrung`.


    Ich würde das in eine Coroutine kapseln, die kann die Zeit der letzten Ausführung ja intern "behalten":



    Gruß, noisefloor

  • Hallo zusammen,

    auf die Schnelle erstmal ein Dankeschön für die ersten Antworten.

    Werd ich mir daheim dann genauer ansehen, vor allem den Ansatz mit der Coroutine von noisefloor find ich sehr interessant.

    Im Moment bin ich Brötchenverdienen und da ist leider nix mit Progrämmchen ausprobieren (so gerne ich das jetzt tun würde).


    Tell ,

    das mit dem Hin- und Herschieben der Variable war mir schon klar. Ich wollte das halt gerne vermeiden, weil ich nach einer eleganteren Methode Ausschau halten möchte. Gerne will ich auf dem Weg dorthin etwas lernen aber selbst mit der ganzen Literatur, die ich dazu habe (und auch lese...) fehlt mir da scheinbar der richtige Funke, um den Einstieg zu finden. Wenn die bessere Lösung also ein Klasse wäre...wie könnte sowas aussehen?


    Grüße,

    Raspbuino

  • Hallo,


    Zitat

    das mit dem Hin- und Herschieben der Variable war mir schon klar. Ich wollte das halt gerne vermeiden, weil ich nach einer eleganteren Methode Ausschau halten möchte


    Na ja, das ist halt so, wenn man mit Funktionen programmiert. Das ist schon die richtige "Eleganz".

    Im Prinzip ist das bei Klassen auch nicht anders, nur das die Methoden der Klasse dann die Attribute der Klasse ändert.


    Die Methode mit der Coroutine ist hier zwar "eleganter" - aber Corountinen kann man lange nicht überall (sinnvoll) einsetzen.


    Gruß, noisefloor

  • Hallo nochmal,

    so...Feierabend und schon wieder vor der Kiste... :)

    Zitat

    Na ja, das ist halt so, wenn man mit Funktionen programmiert. Das ist schon die richtige "Eleganz"Das

    Das nehm ich dann gerne mal so mit! Ich denke, so mach ich das erstmal. Allerdings ist es so, dass ich mehr als eine Aktion hab, die zyklisch durchgeführt wird (aktuell zwei und zwar mit unterschiedlichen Frequenzen). Das heißt, ich muss zwei Variablen allein schon deswegen an die Funktion übergeben.

    Das mit yield bzw einer Generatorfunktion kannte ich bisher gar nicht. Hab das in meinem schlauen Buch grad nachgelesen und den Code ausprobiert. Sehr interessant - wär ich ansonsten sicherlich nicht so ohne Weiteres drübergestolpert.

    Das mit dem i-Tüpfelchen, nämlich einer Klasse, würde mich trotzdem interessieren. Vielleicht krieg ichs irgendwann noch gebacken.


    Vielen Dank soweit für die Hilfe! :thumbup:


    BTW: ( Linus ) die Variablennamen überarbeite ich auch nochmal. Bin ich eh grad dabei; hab mir letzte Woche im Buchladen "Clean Code" gegönnt:

    "details matter"!


    Grüße,

    Raspbuino

  • Das mit yield bzw einer Generatorfunktion kannte ich bisher gar nicht

    yield ansich kannte ich - das mit den Coroutinen ist mir völlig fremd, genauso dass dann eine Methode .send zur Verfügung steht.

    Bin grad am Simulieren von noisefloor s code :) Ich weiß schon warum ich immer mitlese...

  • Hallo,


    Coroutinen trifft man in der "freien Wildbahn" auch selten an bzw. man braucht das auch selten. Die ursprüngliche Idee ist auch, das man mit Python nebenläufige Programmierung mit nur einem Thread (in dem das Programm an sich läuft) realisieren kann.

    Wer sich dafür interessiert: Dave Beazley gilt als der Guru für Python Coroutines und es gibt diverse Vorträge von ihm (auch auf Youtube) zu dem Thema.


    Coroutinen sind mit asyncio, also ab Python 3.4, populärer geworden, weil asyncio massive auf Coroutinen setzt.


    Gruß, noisefloor

  • Danke für den Tipp! Könnte durchaus für mich interessant sein, weil es geht dabei durchaus darum, so manche Dinge mehr oder weniger parallel zu tun. Aber jetzt treib ich das erstmal so voran, bis es getestet werden kann und dann schau mer mal, wo ggf die Grenzen dabei liegen, wie ich es mache. Vielleicht ist es auch gar kein Problem. Aber mein Ziel ist nicht allein, die Geschichte "irgendwie" zum Laufen zu kriegen, sondern durchaus mit dem Anspruch, einen halbwegs gut wartbaren Code zu schreiben, der vielleicht auf seine Art auch, nun ja, schön ist. Und deswegen nehm ich den Hinweis weiter oben hinsichtlich Konventionen bei Namensgebung von Variablen ernst.

    Grüße,

    Raspbuino

  • Cool - was es alles gibt !

    Für meinen Geschmack sind da ein paar zuviel_Unter_striche unterwegs aber ich finde es gut, wenn es sowas gibt, an dem man sich orientieren kann.

    Grüße,

    Raspbuino

  • Und wieso muß das Timekeeping überhaupt über Klassen und Funktionen verstreut werden? Wieso kann man nicht einen zentralen Timekeeper haben, der einzelne Workerfunktionen einfach aufruft OHNE, daß diese irgendwelche Zeitfunktionalitäten beinhalten?


    Auf diese Weise kann der "Zeitmaster" nämlich u.a. auch Zeitrundungsfehler behandeln, die allfällig mit diesen Sleep-Funktionen entstehen. Will man zeitequidistant ohne Rundungsfehler etwas durchführen, dann definiert man eine Zählvariable, die für jedes Zeitntervall das Produkt aus ihrem Count * Zeitspanne bestimmt. Ist dieser Wert überschritten, dann wird die Workerfunktion ausgeführt - no less no more.


    Was ergibt Sleep(10)+Sleep(10)+sleep(0)? Etwa sleep(30)? Naja, höchstens so ungefähr. Sogar 1.1+1.1+...+1.1 n mal ausgeführt (also Schedulerartefakte eines Sleep außer Acht gelassen) ist bei weitem nicht so genau wie n*1.1! Das liegt in der Natur der IEEE Zahlendarstellung mit deren endlichen Mantisse.

  • Der Service "Zen of Python" funktioniert jetzt auch bei mir. Das war mal wieder Situationskomik vom Feinsten. :lol:


    Sorry nochmals für den OT!

    "Alles, was wir sind, ist Sand im Wind, Hoschi."

  • Eine Variante mit einer Klasse: