Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

in python , why is there a difference in exception when signal handling is done before and after "try except"

I recently started with python . I was playing with handling the keyboard interrupt , when I came across this behavior

import signal,sys

def handleInt(sign,no):
    print "interrupted"

signal.signal(signal.SIGINT,handleInt)    # exception raised is IOError

try:
    sys.stdin.read(1)
except IOError:
    print "io interrupt"

but if I change the signal handling to after the try-except

import signal,sys

def handleInt(sign,no):
    print "interrupted"

try:
    sys.stdin.read(1)
except KeyboardInterrupt:
    print "keyboard interrupt"

signal.signal(signal.SIGINT,handleInt)    # exception raised is KeyboardInterrupt

When I press ctrl+c , there is a difference in the exception in the two cases .So why is this behavior ?

like image 396
karyboy Avatar asked Jul 26 '13 09:07

karyboy


1 Answers

Python has its own built-in singal handler for SIGINT. This handler simply raises KeyboardInterrupt. In your first code, you replaced the built-in handler with the new handler hence you see this output:

$python test_exc.py 
^Cinterrupted

Note that io interrupted is not printed, since no exception was raised. In fact modifying the code to:

import signal,sys

def handleInt(sign,no):
    print "interrupted"

signal.signal(signal.SIGINT, handleInt)    # exception raised is IOError

try:
    sys.stdin.read(1)
except IOError:
    print "io interrupt"
else:
    # else is executed only if no exception was raised
    print "done"

You get:

$python test_exc.py 
^Cinterrupted

done

Note that hitting Ctrl+C does not block the call to sys.stdin.read(1) hence you still have to press some key to let the program continue. Raising an exception inside the signal handler will raise it as if the call to sys.stdin.read(1) produced it:

import signal,sys

def handleInt(sign,no):
    print "interrupted"
    raise OSError

signal.signal(signal.SIGINT, handleInt)    # exception raised is IOError

try:
    sys.stdin.read(1)
except IOError:
    print "io interrupt"
else:
    # else is executed only if no exception was raised
    print "done"

Sample run:

$python test_exc.py 
^Cinterrupted
Traceback (most recent call last):
  File "test_exc.py", line 10, in <module>
    sys.stdin.read(1)
  File "test_exc.py", line 5, in handleInt
    raise OSError
OSError

Note: you can access the default signal handler via signal.default_int_handler.

like image 146
Bakuriu Avatar answered Sep 21 '22 10:09

Bakuriu