Seite 1 von 1
KeyboardInterrupt abfangen und an Nachfrage weiterleiten
Verfasst: Montag 29. Oktober 2007, 10:13
von der_dan
Hallo,
ich habe eine kurze Frage. Ich habe ein Programm das über
quasi permant läuft. Per STRG+C kann man das ja beenden nun möchte ich aber vorher eine Art Sicherheitsabfrage einbauen à la: "Wollen Sie wirklich beenden? (N/j)"
Ich würde also einen
Code: Alles auswählen
try:
while True:
meinProgram...
except KeyboardInterrupt:
Block anlegen und dort die Frage einbauen nur wie würde ich bei "nein" einfach in while fortfahren?
Vielen Dank für eure Ideen oder Hilfen!
Viele Grüße
Daniel
Verfasst: Montag 29. Oktober 2007, 10:32
von BlackJack
Falsche Schachtelung. Wenn die Ausnahme ausserhalb der Schleife behandelt wird, führt kein Weg mehr in die Schleife hinein. Du musst innerhalb der Schleife behandeln und wenn der Benutzer beenden will die Schleife zum Beispiel mit ``break`` abbrechen.
Verfasst: Montag 29. Oktober 2007, 10:45
von Jona
hi,
seltsam, kann das einer erklären?
dieser code funktioniert (KeyboardInterrupt wird abgefangen und MyKeyboardInterrupt geworfen)
Code: Alles auswählen
while True:
try:
print "hello"
except KeyboardInterrupt:
raise Exception, "MyKeyboardInterrupt"
steht aber nur ein "pass" in der schleife wird KeyboardInterrupt nicht abgefangen:
Code: Alles auswählen
while True:
try:
pass
except KeyboardInterrupt:
raise Exception, "MyKeyboardInterrupt"
Verfasst: Montag 29. Oktober 2007, 10:53
von Rebecca
Nein, aber bei mir tritt das auch auf (Python 2.4 und 2.5 unter Debian Testing).
Verfasst: Montag 29. Oktober 2007, 11:23
von Jona
es wird noch spassiger:
bei diesem code scheint es von der gerade in der abarbeitung befindlichen codezeile abzuhängen was passiert.
Code: Alles auswählen
def raiser():
if False:
raise Exception
def no_raise():
if False:
pass
while True:
try:
#raiser()
no_raise()
except KeyboardInterrupt:
raise Exception, "MyKeyboardInterrupt"
nichts geändert am code während den aufrufen:
Code: Alles auswählen
C:\working_copy\source\test>python py_keybint.py
Traceback (most recent call last):
File "py_keybint.py", line 20, in <module>
raise Exception, "MyKeyboardInterrupt"
Exception: MyKeyboardInterrupt
C:\working_copy\source\test>python py_keybint.py
Traceback (most recent call last):
File "py_keybint.py", line 14, in <module>
while True:
KeyboardInterrupt
Verfasst: Montag 29. Oktober 2007, 12:13
von der_dan
Hmm, irgendwie stehe ich ein wenig auf dem Schlauch... Bis jetzt:
Code: Alles auswählen
import string
while True:
try:
print "Laufe durch und tue dies"
print "Laufe durch und tue und das"
print "Laufe durch und tue und jenes"
print "Laufe durch und tue noch viel mehr"
except KeyboardInterrupt:
while True:
confirm = raw_input('Enter "yes" to cancel or "no" to keep running [yes/no]:').strip().lower()
if confirm == 'yes':
print "Cancel!"
break
elif confirm == 'no':
print "Keep runnning!"
pass
else:
print ('Sorry, no valid answer...')
pass
print "Draussen"
Das klappt aber noch nicht so richtig. Was mir gerade dazu eingefallen ist, nach Auslösen des KeyboardInterruptes und Beantwortung mit "Nein, soll weiterlaufen"
wird dann an der Stelle weitergemacht wo das Programm vorher stand? Oder fängt die Schleife dann wieder komplett neu an?
Ich möchte also einfach sicherstellen das der Benutzer nicht aus Versehen das Programm stoppt - im Fall des Falles (doch mal STRG-C gedrückt) soll es aber einfach weitermachen. Geht das dann überhaupt? Oder brauche ich einen ganz anderen Ansatz. Das ganze ist ein Task, der halt die ganze Zeit quasi im Hintergrund laufen sollte aber ab und an sind die Konsolenausgaben wichtig.
Verfasst: Montag 29. Oktober 2007, 13:05
von Jona
wird der interrupt ausgelöst, so wird aus dem try-block rausgesprungen.
hier würde dann also (falls der nutzer das so will) ein neuer schelifendurchlauf gestartet werden.
du musst dann also im except block (oder in finally) sicherstellen, dass das programm in einem definierten (vernünftigen) zustand ist.
zu deinem code: überleg mal was bei dem break bei cancel passiert ...
Verfasst: Montag 29. Oktober 2007, 13:32
von der_dan
Mhmm, ok. Dann hilft mir dieser Ansatz nicht unbedingt weiter. Gibt es keine Möglichkeit die Unterbrechung
vorher abzufangen? Also bevor "unterbrochen" wird?
zu deinem code: überleg mal was bei dem break bei cancel passiert ...
Ok, das break springt zurück in die while Schleife. Das will ich natürlich nicht. Also dann besser das Programm mit exit() beenden?
Verfasst: Montag 29. Oktober 2007, 13:45
von CrackPod
Hallo,
wie wärs, wenn du einfach das "Programm" also die Ausgabe in eine Funktion kapselst?
Code: Alles auswählen
def a():
print a
def main():
try:
a()
except KeyboardInterrupt:
confirm = raw_input('Enter "yes" to cancel or "no" to keep running [yes/no]:').strip().lower()
if confirm == 'yes':
break
else:
continue
if __name__=='__main__':
main()
LG
Verfasst: Montag 29. Oktober 2007, 13:54
von Rebecca
CrackPod hat geschrieben:wie wärs, wenn du einfach das "Programm" also die Ausgabe in eine Funktion kapselst?
Das aendert nichts am Problem.
Verfasst: Montag 29. Oktober 2007, 13:55
von BlackJack
@der_dan: Du solltest vielleicht an die Quelle gehen und verhindern dass das entsprechende Signal vom Betriebssystem an den Prozess nicht ausgewertet wird. Geht vielleicht mit dem `signal`-Modul.
Grundsätzlich halte ich das für keine gute Idee. Programme die sich nicht mit SIGINT abbrechen lassen und mich zwingen `ps` und `kill` oder `killall` zu bemühen, finde ich jedenfalls ziemlich nervig.
Verfasst: Montag 29. Oktober 2007, 14:26
von Jona
blackjack, hast du eine idee bzgl des seltsamen verhaltens das python hier an den tag legt?
Verfasst: Montag 29. Oktober 2007, 15:20
von BlackJack
Tja, da treffen wohl asynchrone Signalbehandlung in C und ein Interpreter unglücklich aufeinander. Wahrscheinlich wird auf dieses Signal nur bei bestimmten Bytecode-Befehlen geprüft um es in eine Ausnahme umzuwandeln und bei so grundlegende Sachen wie Sprungbefehlen wird nicht geprüft um Schleifen nicht auszubremsen. Und wenn in der Schleife "nichts" gemacht wird, wird halt auch nicht auf das Signal geprüft.
Wenn es stört, sollte man vielleicht einen Bug-Report absetzen.
Verfasst: Montag 29. Oktober 2007, 16:53
von der_dan
BlackJack hat geschrieben:@der_dan: Du solltest vielleicht an die Quelle gehen und verhindern dass das entsprechende Signal vom Betriebssystem an den Prozess nicht ausgewertet wird.
Danke für den Tipp! Das werde ich mir mal ansehen. Wie du schon geschrieben hast ist das natürlich ziemlich brachial
Ansonsten werde ich wohl den Code entsprechend umstellen und das ganze irgendwie als Hintergrundprozess realsieren und den Rest irgendwie über eine Art "logging" abbilden.
Verfasst: Dienstag 30. Oktober 2007, 10:33
von der_dan
Ich habe mit "signal" experimentiert und bin dank BlackJack und diesem
Posting zu einer Lösung gekommen. Sieht so aus:
Code: Alles auswählen
import string
import signal
import sys
import itertools
from time import sleep
def onexit(signum, handler):
print('STRG+C pressed! (Signal: %s)' % (signum,))
while True:
confirm = raw_input('Enter "yes" to cancel programm now or "no" to keep running [yes/no]:').strip().lower()
if confirm == 'yes':
print "Cancel!"
sys.exit()
elif confirm == 'no':
print "Keep runnning!"
break
else:
print ('Sorry, no valid answer...')
pass
signal.signal(signal.SIGINT, onexit)
counter = itertools.count()
# Angenommen hier wäre mein eigentliches Programm
while True:
print counter.next()
sleep(2)
Ist scheinbar das, was ich gesucht habe. Zumindest läuft der "Simulations-Counter", der mein Programm darstellen soll an der Stelle weiter wo ich ihn erwarte. Vielleicht übersehe ich auf Grund meiner leider noch begrenzten Python Kenntnisse allerdings etwas? Wie sieht es mit Threads aus? Kann ich das so machen? Was meint ihr?
Danke!
Verfasst: Donnerstag 1. November 2007, 09:39
von der_dan
Eine Verständnis-Frage dazu habe ich noch. Der Zähler läuft zwar weiter, aber wie verhält es sich mit Threads, die noch im Hintergrund laufen?
Was passiert jetzt bei STRG+C genau? Wird das komplette Programm "angehalten", "eingefroren" und nach dem break:
gehts halt einfach weiter?
Danke euch!
Verfasst: Dienstag 27. November 2007, 13:27
von der_dan
sorry, wenn ich den nochmal rauskrame aber ich bin diesbezüglich leider noch nicht weiter...
Mir gehts darum: Wird die Ausführung des Programms inkl. aller Threads nach dem SIGINT / STRG+C "angehalten/eingefroren" oder laufen die Threads im Hintergrund einfach weiter und sobald ich dann den Abbruch bestätige bin ich "irgendwo" im Code?
Danke!