while mit tastendruck abbrechen

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
Benutzeravatar
draufunddran
User
Beiträge: 34
Registriert: Freitag 26. Juni 2009, 13:43

Hallo leute,

bin sehr neu im Bereich Python, und hab mal ein für sicherlich einfache frage.

Ich habe eine "While-Schleife" und würde die gerne so lange laufen lassen bis eine bestimmte Taste gedrück wurde.

mit raw_input geht es ja nicht, da er ja dann so lange wartet bis er eine Eingabe hat oder?

greetz draufunddran
Benutzeravatar
limepix
User
Beiträge: 37
Registriert: Dienstag 11. November 2008, 16:54

auf windows systemen kannst du n programm mit Ctrl-C abbrechen. um den fall abzufangen könntest du das folgendermaßen machen:

Code: Alles auswählen

try:
    while 1:
        print '.'
except KeyboardInterrupt:
    print 'Stop'
greetz ;)
Benutzeravatar
HerrHagen
User
Beiträge: 430
Registriert: Freitag 6. Juni 2008, 19:07

Wenn du Windows nutzt, wäre das Modul msvcrtvielleicht etwas für dich.
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

limepix hat geschrieben:auf windows systemen kannst du n programm mit Ctrl-C abbrechen.
Das geht auch auf Nicht-Windows Systemen.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

limepix sagt trotzdem die Wahrheit :wink: Um on-topic zu bleiben: für UNIX-ähnliche Betriebssysteme gibts noch curses.
problembär

Ich glaube, curses macht in der Linux-Konsole so ein Fenster auf, das man nicht haben will.

Für ungeblockte Tastenabfragen in der Linux-Konsole gab's stattdessen mal den KeyHandler.

Für Python-Anfänger aber wohl etwas schwer zu benutzen :roll:.

Gruß
lunar

Weder ein Anfänger noch sonst irgendjemand sollte diesen Code verwenden. Er ist unschön und unnötig komplex, und noch dazu fehlerbehaftet. Das geht kürzer, eleganter und allgemein besser.
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

Wieso gibt's da keine betriebssystemunabhängige Implementierung in Python?
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Zum einen wäre die einzig halbwegs plattformunabhängige Variante über curses, wobei Python für Windows dies nicht in der Standardinstallation einem zur Verfügung stellt. Zum anderen bin ich mir auch nicht sicher, ob es eine solche Funktion in curses gibt.

Eventuell könnte man das nachbauen mit einen Thread und curses.getch() oder über eine grafische Anwendung(mit GUI).
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
lunar

mkallas hat geschrieben:Wieso gibt's da keine betriebssystemunabhängige Implementierung in Python?
Die Antwort ist einfach: Niemand hat das so sehr gebraucht, um sich für eine Aufnahme in die Standardbibliothek einzusetzen.

@darktrym
Das lässt sich schon plattformunabhängig implementieren. Die Lösung über "termios" sollte unter jedem modernen Unix-Derivat laufen, für Windows enthält die Standardbibliothek bereits eine entsprechende Funktion.
problembär

lunar hat geschrieben:Das geht kürzer, eleganter und allgemein besser.
Nur schade, daß da für das Einlesen jedes einzelnen Zeichens die Terminal-Einstellungen umgestellt werden.

(Außerdem beruht die dort genannte Funktion ebenfalls auf dem dort weiter oben gezeigten KeyHandler-Code.)

Gruß
lunar

Ich denke nicht, dass es ein Problem darstellt, wenn die Terminaleinstellungen jedes Mal geändert werden. Selbst auf alten Systemen sollte das keine für den Nutzer spürbaren Verzögerungen nach sich ziehen. Falls das der Fall ist, kann man dieses Problem relativ trivial lösen.

Durch die Verwendung der with-Anweisung ist garantiert, dass das Terminal unter allen Umständen wieder in den Ausgangszustand versetzt wird. Das ist bei keiner deiner Varianten der Fall. Die erste setzt das Terminal im Falle einer Ausnahme gar nicht zurück. Die zweite Variante versucht, dazu den Destruktor zu nutzen, obwohl Python nicht garantiert, dass dieser unter allen Umständen aufgerufen wird. Außerdem garantiert Python die Existenz globaler Namen zu diesem Zeitpunkt nicht mehr, so was diesen unschönen lokalen Import erforderlich macht. In der zweiten Variante wird zudem eine Methode aufgerufen, die gar nicht definiert ist.

Ich denke übrigens nicht, dass jerchs Funktion auf deinem Code basiert. Die einzige Gemeinsamkeit ist der eh unvermeidliche Aufruf von "tcsetattr()" und "tcgetattr()" zum Speichern und Wiederherstellen des Status. Ansonsten ist so ziemlich alles anders, so nutzt er "ttc.setcbreak()", wo du die Terminaleinstellungen manuell manipulierst. Außerdem verzichtet die Funktion auf den nicht portablen Aufruf von "fcntl()" (dessen Sinn ich in deinem Code eh nicht ganz verstehe).
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Naja für non-blocking read wäre eine fcntl-Manipulation unter älterer Python-Version durchaus interessant. Die getch-Funktion des curses-Modul unterstützt das meines Wissens nach, ich hatte da bewußt drauf verzichtet.

@problembär:
Ich hab Deine Version nicht mehr parat (und den Link nicht verfolgt :oops:), mir war da damals aber zuviel magic drin, unklare und unsinnige Strukturierung mit Klassenentwurf, Zustands-Inkonsistenzen etc.
Kurzum ich würde den Code so nicht weiterempfehlen. Ist nicht persönlich gemeint, nur kann jmd., der relativ neu in der Sprache ist, so etwas gar nicht abschätzen und läuft Gefahr, mit fehlerhaftem Code zu arbeiten.

Eine vereinheitlichende Modul-Implementation für die gängigen Plattformen ist ziemlich einfach machbar, mit kbhit-Funktionalität, non-blocking und Unicode-Unterstützung wirds etwas komplexer. Falls Interesse besteht, schiebe ich die gern nach...

BTW, um die curses-Unterstützung in Python ist es auch nicht so gut bestellt (Zukunft des Moduls?), vllt. sollte man daran was machen.

Grüße jerch
problembär

Ok, ich wußte die Terminal-Einstellungen auch nicht aus dem Kopf, das heißt, ich hab' die paar Zeilen Code ja auch aus irgendwelchen Tutorials und Postings zusammengeschraubt. Ist eigentlich egal, wo das nun herkam, es ist jedenfalls, wie man's macht, die Module lassen ja auch kaum was anderes zu.

Mal angenommen, man wollte die Terminal-Einstellungen nur einmal setzen, dann eine gewisse Zeit ungeblockt einlesen, und am Ende wieder zurückstellen.
Ist es da so abwegig, eine Funktion "setTerminalToUnblockedReading()" und eine Funktion "setTerminalBack()" zu machen, und wenn man dann schon zwei Funktionen hat, die in einer Klasse zusammenzufassen? Liegt doch irgendwie nahe ...

Gruß
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Auf die Designschwächen Deines Klassenansatzes ist ja nun schon mehrfach hingewiesen worden. Was soll das sys.exit da drinnen? Hast Du Dir über die Seiteneffekte/Terminalzustand mal Gedanken gemacht? (Das __del__ macht es eigentlich nur noch schlimmer.)
Deine Klasse ist nichts weiter als eine Ansammlung von Funktionen und Terminalsettings. Dann setzt Du den raw-Modus im Konstruktor der Klasse. Was passiert jetzt wohl bei multiplen Importen und Instantiierungen (hässliches denglish) in verschiedenen Modulen?
Auf all diese Dinge haben lunar und str1442 schon hingewiesen.

Fummeleien an so lebenswichtigen Ressourcen wie stdin/stdout sollten sich auf ein Minimum beschränken bzw. so schnell wie mgl. den Ausgangszustand restaurieren. Oder aber mit klarer API wie bei curses (initscr()) die Verantwortung an den Nutzer durchreichen, in der Hoffnung, das dieser damit umzugehen weiß. Magic wie - oh jetzt hab ich KeyHandler() aufgerufen, warum geht das Terminal bloß nicht mehr - sind in meinen Augen ein Designfehler.
lunar

problembär hat geschrieben:Ist es da so abwegig, eine Funktion "setTerminalToUnblockedReading()" und eine Funktion "setTerminalBack()" zu machen, und wenn man dann schon zwei Funktionen hat, die in einer Klasse zusammenzufassen? Liegt doch irgendwie nahe ...
Klassen verbinden Daten und zugehöriges Verhalten und sind nicht bloß Namensräume für Funktionen.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

lunar hat geschrieben:Durch die Verwendung der with-Anweisung ist garantiert, dass das Terminal unter allen Umständen wieder in den Ausgangszustand versetzt wird.
Es kann durchaus mal wichtig sein: "__exit__" wird nicht in jedem Fall aufgerufen. *POWER OFF*.
Das Leben ist wie ein Tennisball.
lunar

Dann ist der Zustand des Terminals dein geringstes Problem ;)
Antworten