Anfängerproblem - Schleife programmieren

  • Hallo,
    ich habe ein ziemliches Anfängerproblem. Ich habe in Python ein Script, dass mir die Kommandozeile auf einem Display ausgibt. Da ich nur 16 Zeichen Platz habe scrollt der Text dann durch.
    Mein Problem ist nun, dass das Script nicht das Display aktualisiert, also im Prinzip danach 5s Pause macht und es dann wieder abspielt.

    Das Script beinhaltet folgendes. Der Rest zum Ansteuern der Hardware habe ich weggelassen, da sich da ja nichts ändern kann.

    Kann mir irgendjemand einen Ratschlag geben, wie ich da weiter komme? ::)

    Vielen Dank

  • Was wir sofort auffällt ist das du den "f" handle nicht mehr schließt - das is böse :fies:

    Das nächste wäre das du den Konsolenbefehl "date" ausführst um das aktuelle Datum zu kriegen? Wieso machst du das nicht nativ/pure in Python?

    Ich glaub besser wäre es wenn du das komplette Script zeigst - dann könnte man denk ich dein Problem auch besser nachvollziehen.

  • Ups, da muss ich dann nochmal Kosmetik betreiben :D


    Wie meinst du das mit dem Datum? Das war für mich die einfachste Art es ans Display zu senden.
    Ich habe das Datum jetzt einfach als Platzhalter verwendet, es kann auch sein, dass ich statt "date" später "Temperatur" o.ä. auslese, so muss ich dann nur den Konsolenbefehl abändern.

  • Hallo,

    Zitat

    Wie meinst du das mit dem Datum? Das war für mich die einfachste Art es ans Display zu senden.


    Es ist immer einfacher & besser, ein Python-Modul zu nehmen, als einen externen Befehl:

    [code=php]>>> import datetime
    >>> datetime.date.today()
    datetime.date(2015, 12, 19)
    >>> datetime.datetime.today()
    datetime.datetime(2015, 12, 19, 17, 13, 16, 130948)
    >>> heute = datetime.datetime.today()
    >>> print(heute)
    2015-12-19 17:13:35.275579
    >>>[/php]

    Gruß, noisefloor

  • Es gibt immer mehrere Wege etwas zu lösen - ich bevorzuge [code=php]>>> import time
    >>> print time.strftime("%d.%m.%Y %H:%M:%S")
    19.12.2015 17:36:06
    >>> [/php]

    Die von noisefloor gezeigte Methode ist - zumindest was das print angeht - für Python3.

    Ein paar weitere Optimierungsvorschläge:

    - Wenn man mehrere nachfolgende ' if ' Abfragen nutzt dann am besten " elif " nehmen, denn es kann bei deiner lcd() Funktion ja nur eins von beidem zutreffen: Wenn zeile == 1 ist brauch die zweite Abfrage nicht auch noch geprüft werden.
    - Du nutzt unterschiedliche Einrückungen - mal 4 Leerzeichen, mal nur 2. Besser wärs wenn du das einheitlich machst, Python ist was das angeht ziemlich pingelig.
    - Wie bereits erwähnt schließt du die " f " handler nicht.. Das kann zum absturz führen da das Betriebssystem (nicht nur Linux) nicht unendlich viele "Datei Handler" auf haben kann. Ich würde dir aber empfehlen das "which"-Statement zu verwenden, das kümmert sich selbstständig ums schließen nachdem die Einrückung beendet wurde.
    - Es gibt ein Python Module für MPD: https://github.com/Mic92/python-mpd2

    Und dann glaub ich das dein Script nach einmaligen scrollen des Titels, sich beendet da es dort keine übergeordnete Schleife gibt - also nachdem "for i in range (0, len(titel))" durchlaufen ist wars das. Kann das sein? :huh:

  • ... Und dann glaub ich das dein Script nach einmaligen scrollen des Titels, sich beendet da es dort keine übergeordnete Schleife gibt - also nachdem "for i in range (0, len(titel))" durchlaufen ist wars das. Kann das sein? :huh:
    ...

    So ist es :D
    Mit richtiger EInrückung
    [code=php]f=os.popen("date")
    for i in f.readlines():
    date = i
    lcd(1, titel)
    lcd(2, date)
    time.sleep(1)
    for i in range (0, len(titel)):
    lcd_byte(DISPLAY_LINE_1, DISPLAY_CMD)
    lcd(1, titel[i:(i+15)])
    time.sleep(0.4)
    lcd_byte(DISPLAY_LINE_1, DISPLAY_CMD)
    lcd(1, titel[i:(i+15)])[/php]
    sollte es funktionieren.

    Allerdings finde ich auch die Art und Weise das Datum abzufragen schon sehr umständlich.

  • Zitat

    - Wenn man mehrere nachfolgende ' if ' Abfragen nutzt dann am besten " elif " nehmen, denn es kann bei deiner lcd() Funktion ja nur eins von beidem zutreffen: Wenn zeile == 1 ist brauch die zweite Abfrage nicht auch noch geprüft werden.


    Muss ich nicht beides abfragen, um dann Zeile 1 und Zeile 2 zuzuordnen?
    Das ist ja ein zweizeiliges Display.
    Also wenn Zeile = 1 dann gibt er Zeile 1 aus und wenn Zeile = 2 gibt er das für die 2. Zeile aus.

    Zitat


    - Du nutzt unterschiedliche Einrückungen - mal 4 Leerzeichen, mal nur 2. Besser wärs wenn du das einheitlich machst, Python ist was das angeht ziemlich pingelig.


    Danke für den Hinweis. Ich bringe mir das alles selbst bei und komme eher aus dem HTML/CSS Bereich, da war mir das nicht bewusst.

    Zitat

    Und dann glaub ich das dein Script nach einmaligen scrollen des Titels, sich beendet da es dort keine übergeordnete Schleife gibt - also nachdem "for i in range (0, len(titel))" durchlaufen ist wars das. Kann das sein?


    Genau das war meine Ursprungsfrage. Das Script läuft ja gerade nur 1x durch und beendet sich dann.
    Meine Überlegung war, das Ganze in eine Schleife zu setzen und immer wieder ablaufen zu lassen. Im Prinzip Script durchlaufen - 5 Sekunden warten - Script durchlaufen - 5 Sekunden warten - ....
    Da gibt es aber sicher eine schönere Lösung :D

    Zitat

    Allerdings finde ich auch die Art und Weise das Datum abzufragen schon sehr umständlich.


    Ja danke :) Hab ich verstande und werde es ändern.
    Aber wie gesagt, dass stand ursprünglich mal die Radiostation oder so und ich hab dann nur das Datum genommen, weil man da besser eine Aktualisierung sieht. Soll nicht in der finalen Version drin sein.

    Einmal editiert, zuletzt von elkloso (19. Dezember 2015 um 17:51)

  • So ich hab eure Ratschläge jetzt mal eingebaut. Danke :)

    Zur Schleife:
    Kann ich das eig. Script nicht einfach in eine "while- Schleife" setzen, die sich nie erfüllen wird?
    Wäre wohl ziemlich gebastelt aber sollte doch laufen oder?

    Also im Prinzip setze ich ein "while x < 1:" davor und definiere dann x=0 und dann läuft die Schleife ewig weiter.
    Das tut schon beim Schreiben weh, aber eine andere Idee hab ich gerade nicht :D

  • Hallo,

    der folgende Python 2 Code läuft unendlich lange über einen String und gibt durchlaufend einen Abschnitt der Länge `slice_length` zurück. Wenn der String am Ende ist, wird wieder von vorne begonnen:

    [code=php]from time import sleep

    def text_slice_yielder(text, length):
    text_length = len(text)
    diff = text_length - length
    counter = -1
    while True:
    if counter <= diff+1:
    counter = counter + 1
    yield text[counter:text_length-length+counter]
    else:
    counter = -1

    my_text = 'ABCDEFGHIJ'
    slice_length = 6
    my_slice = text_slice_yielder(my_text, slice_length)

    while True:
    print(my_slice.next())
    sleep(1)[/php]


    Statt des `print` in der `while True` Schleife musst du halt deine Code zur Aktualisierung des Displays schreiben.

    Gruß, noisefloor

  • framp: Das würde doch auch nichts bringen.. Datum wird nur ein mal ausgelesen, gibt nur eine Zeile aus und somit ist die for dann auch nach einem Durchgang beendet.



    Nope, falsche Aussage. Das ist 1:1 Copy&Paste aus der Python 2.7.9. Konsole von Jessie (Hint: Python 2.7 kennt ootb print als Statement und print als Funktion - auch ohne __future__ Import) :)

    Dem muss ich leider widersprechen. Python 2.7 tut zwar bei print("bla") dem Anschein nach auch das was python3 in dem Fall tut, allerdings ist das Verhalten trotzdem anders. In python 2.x ist print keine Funktion, auch nicht in 2.7.
    Wieso? Siehe hier:

    Siehst du den Unterschied? :fies:

    Im Vergleich dazu in Python3:

    Code
    pi@raspberrypi:~$ python3
    Python 3.4.2 (default, Oct 19 2014, 13:31:11) 
    [GCC 4.9.1] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> print("a","b","c")
    a b c
    >>>

    Dazu hatte ich hier auch schon unerträgliche Diskussionen mit unserem Python PEP Guru bootsmann..



    Muss ich nicht beides abfragen, um dann Zeile 1 und Zeile 2 zuzuordnen?
    Das ist ja ein zweizeiliges Display.
    Also wenn Zeile = 1 dann gibt er Zeile 1 aus und wenn Zeile = 2 gibt er das für die 2. Zeile aus.

    Der Aufruf der Funktion erfolgt nur ein mal, also wird der Code auch nur ein mal verarbeitet. Du machst 2 Aufrufe nacheinander:
    [code=php]
    lcd(1, titel)
    lcd(2, date)
    [/php]Und übergibst bei jedem Aufruf die Zeilennummer die verwendet werden soll. Also kann jeweils nur eine der beiden ' if ' zutreffen. In deinem Fall würde zum Beispiel beim Aufruf von "lcd(1, titel)" die erste if greifen, dann prüft er bei dir aber noch die 2.if obwohl das ja gar nicht mehr zutreffen kann... Deshalb macht es in solch einem Fall mehr Sinn "if ... elif" zu verwenden, das spart zwar nur microsekunden aber Kleinvieh macht auch Mist :)
    Also besser:
    [code=php]
    #Display Zeilen schreiben
    def lcd(zeile, text):
    if zeile == 1:
    lcd_byte(DISPLAY_LINE_1, DISPLAY_CMD)
    elif zeile == 2:
    lcd_byte(DISPLAY_LINE_2, DISPLAY_CMD)

    message = text.ljust(DISPLAY_WIDTH, " ")
    for i in range(DISPLAY_WIDTH):
    lcd_byte(ord(message[i]), DISPLAY_CHR)
    [/php]


    Genau das war meine Ursprungsfrage. Das Script läuft ja gerade nur 1x durch und beendet sich dann.
    Meine Überlegung war, das Ganze in eine Schleife zu setzen und immer wieder ablaufen zu lassen. Im Prinzip Script durchlaufen - 5 Sekunden warten - Script durchlaufen - 5 Sekunden warten - ....
    Da gibt es aber sicher eine schönere Lösung :D

    Ja das kannst du auch genau so erreichen ;) In dem Fall dann eben mit einer while.
    Allerdings solltest du allgemein auch zumindest ein "try:" und "except" einbauen damit sich das Script zB mithilfe von STRG+C sauber beenden lässt und die GPIO's nach beenden des Scripts wieder zurückgesetzt werden..

    Also für den Anfang in etwa so:

    [code=php]lcd_init()

    try:
    while True:
    titel = os.popen("mpc current -f %title%").readlines()
    date = time.strftime("%d.%m.%Y %H:%M:%S")
    lcd(1, titel)
    lcd(2, date)
    time.sleep(1)
    for i in range (0, len(titel)):
    lcd_byte(DISPLAY_LINE_1, DISPLAY_CMD)
    lcd(1, titel[i:(i+15)])
    time.sleep(0.4)
    lcd_byte(DISPLAY_LINE_1, DISPLAY_CMD)
    lcd(1, titel[i:(i+15)])
    time.sleep(5)
    except (KeyboardInterrupt, SystemExit):
    GPIO.cleanup()
    print "Quit"
    [/php]


    PS: Das vermischen von verdeutschten und englischen Variable-Namen is auch etwas uncool :fies:

  • Dankeschön. Langsam blicke ich durch :)

    Mein Fehler lag genau darin, worauf ich eben von euch hingewiesen wurde. Nach der while angabe hätte ich den Code einrücken müssen...
    Mea Culpa

    Oh danke für den Hinweis. Ich versuche eig. alles im engl. zu halten, das ist kompatibler.
    titel und title sieht aber auch ähnlich aus :D

    Bearbeitet 19:25

    Einmal editiert, zuletzt von elkloso (19. Dezember 2015 um 19:25)

  • 1 entspricht True
    0 entspricht False

    Also ja, du kannst es auf 1 lassen :)

    Mit einer 1 anstatt True wäre es mit Python 2 sogar schneller. Mit Python 3 macht es aber keinen nennenswerten Unterschied aus (wäre dort minimal schneller mit True anstatt 1).
    Siehe dazu: http://stackoverflow.com/a/3815387


  • framp: Das würde doch auch nichts bringen.. Datum wird nur ein mal ausgelesen, gibt nur eine Zeile aus und somit ist die for dann auch nach einem Durchgang beendet.

    Kommt darauf an wo man die While Schleife unterbringt ;)

    Die Lösung von noisefloor gefällt mir. yield bzw die dahinterliegenden Generatoren sind ein sehr mächtiger semantischer sugar in Python. Ich bin mal auf eine Webseite gestossen (leider habe ich sie nicht mehr gefunden) wo ein Sysadmin damit sein gesamtes Environment monitored hat :thumbs1:

    Allerdings würde ich es etwas anders implementieren. Seit meine C/C++ Zeit versuche ich Indexoperationen auf Strings (In C z.B. strncpy usw) möglichst zu vermeiden. Das ist immer wieder eine Quelle von Programmierfehlern :(

    Anbei meine Lauflichtalternativimplementierung :)

    [code=php]import time

    def lauflicht(text, laenge, start=0):
    assert laenge <= len(text), "Parameter laenge kann maximal %i sein" % len(text) # parameterpruefungen
    assert start < len(text), "Parameter start kann maximal %i sein" % (len(text)-1) # parameterpruefungen
        
    lauflichtText=text+" "+text # verdoppele text
    aktuellePosition=start # anfangspunkt des lauflichtes im text

    while True:
    if aktuellePosition > len(text): # wenn am Ende des textes
    aktuellePosition=0 # fange wieder vorne an
                
    result=lauflichtText[aktuellePosition:aktuellePosition+laenge] # extrahiere den lauftext
    aktuellePosition+=1 # und gehe eine position weiter
            
    yield result # liefere das ergebnis zurueck

    meinLauflichtText="Really, I'm not out to destroy Microsoft. That will just be a completely unintentional side effect."
    meinLauflichtBreite=50
    meinLauflichtIntervall=0.3 # sekunden zwischen den anzeigen

    # initialisiere meinen lauflichtinterator
    meinLauflicht=lauflicht(meinLauflichtText, meinLauflichtBreite)

    # und nun laufe :)
            
    while True:
    print meinLauflicht.next()
    time.sleep(meinLauflichtIntervall)
    [/php]

  • Keine Ahnung was Du mit fragmentiertes Zeichen meinst.

    Vermutlich erstellst Du Deinen Code unter Windows ... da steht <CR><LF> - unter Linux nur <LF>.
    Zur Konvertierung gibt es z.B. ein Tool mit dem Namen dos2unix. Oder Du benutzt einen Editor unter Windows, der das automatisch kann (z.B. notepad++)

  • Ich benutze "Komodo", das sollte eig eine saubere Datei erstellen.

    Naja ich habe im Prinzip <Ausgabe der Zeile> und dahinter dann ein Zeichen mit vier Strichen.
    Ich weiß nur halt nicht, wo das herkommt, da ich ja nur den Zeileninhalt ausgeben lasse und wenn eine leere Zeile ausgegeben wird ist es auch da.

  • Nach ausprobieren habe ich gemerkt, dass der os.popen - Befehl für das Leerzeichen sorgt, keine Ahnung warum.
    Führe ich den Befehl in der Shell aus ist alles gut. Führe ich ihn per Python-Script aus kommt eine Leerzeile ans Ende.

    Code
    import os
    f=os.popen("BEFEHL")
    for i in f.readlines():
      ausgabe=i
    print (ausgabe)

    Das habe ich jetzt einfach entfernt mit

    Code
    ausgabe = i.rstrip()

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!