在python中,为什么在"try except"之前和之后进行信号处理时异常存在差异

kar*_*boy 5 python signals try-except

我最近开始使用python.当我遇到这种行为时,我正在玩处理键盘中断

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"
Run Code Online (Sandbox Code Playgroud)

但如果我将信号处理改为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
Run Code Online (Sandbox Code Playgroud)

当我按ctrl + c时,两种情况下的异常存在差异.那么为什么会出现这种情况?

Bak*_*riu 5

Python 有自己的内置信号处理程序SIGINT。该处理程序只是引发KeyboardInterrupt. 在您的第一个代码中,您将内置处理程序替换为新处理程序,因此您会看到以下输出:

$python test_exc.py 
^Cinterrupted
Run Code Online (Sandbox Code Playgroud)

请注意,io interrupted打印,因为没有引发异常。实际上将代码修改为:

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"
Run Code Online (Sandbox Code Playgroud)

你得到:

$python test_exc.py 
^Cinterrupted

done
Run Code Online (Sandbox Code Playgroud)

请注意,点击Ctrl+C不会阻止调用,sys.stdin.read(1)因此您仍然需要按某个键才能让程序继续。在信号处理程序内引发异常将引发它,就像调用sys.stdin.read(1)产生它一样:

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"
Run Code Online (Sandbox Code Playgroud)

示例运行:

$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
Run Code Online (Sandbox Code Playgroud)

注意:您可以通过访问默认信号处理程序signal.default_int_handler


ayc*_*dee 1

当您尝试在阻塞调用之后注册信号时sys.stdin.read,您实际上永远不会到达那里。

因此,当您按下 Ctrl-C 时,您会遇到异常,这会引发KeyboardInterrupt读取中断并被try.

当您在第一个示例中实际注册信号处理程序时,会发生一些略有不同的情况。中断正在由您的handleInt代码处理。