版本信息:
下面是我正在玩的一小段测试代码。目的是在执行某些代码时忽略CTRL-C
被按下,之后将恢复CTRL-C
行为。
import signal
import time
try:
# marker 1
print('No signal handler modifications yet')
print('Sleeping...')
time.sleep(10)
# marker 2
signal.signal(signal.SIGINT, signal.SIG_IGN)
print('Now ignoring CTRL-C')
print('Sleeping...')
time.sleep(10)
# marker 3
print('Returning control to default signal handler')
signal.signal(signal.SIGINT, signal.SIG_DFL)
print('Sleeping...')
time.sleep(10)
except KeyboardInterrupt:
print('Ha, you pressed CTRL-C!')
在玩这个时我观察到了什么:
CTRL-C
将由异常处理程序处理(按预期方式)。CTRL-C
将被忽略(仍然如预期的那样)CTRL-C
但不会跳转到异常处理程序。相反,Python只是立即终止。另外,请考虑一下:
>>>import signal
>>>signal.getsignal(signal.SIGINT)
<built-in function default_int_handler>
>>> signal.getsignal(signal.SIGINT) is signal.SIG_DFL
False
>>> signal.signal(signal.SIGINT, signal.SIG_DFL)
<built-in function default_int_handler>
>>> signal.getsignal(signal.SIGINT) is signal.SIG_DFL
True
所以最初,虽然信号处理程序被认为是默认的信号处理程序,但它似乎与SIG_DFL
定义的处理程序不同。
如果有人能够对此有所了解,特别是在将信号处理程序恢复到SIG_DFL后忽略异常处理程序。
答案 0 :(得分:14)
Python安装自己的SIGINT
处理程序以引发KeyboardInterrupt
例外。将信号设置为SIG_DFL
将不会恢复该处理程序,而是恢复系统本身的“标准”处理程序(终止解释程序)。
您必须存储原始处理程序并在完成后恢复该处理程序:
original_sigint_handler = signal.getsignal(signal.SIGINT)
# Then, later...
signal.signal(signal.SIGINT, original_sigint_handler)
正如评论中所说的那样,你可以将其表达为context manager:
from contextlib import contextmanager
@contextmanager
def sigint_ignored():
original_sigint_handler = signal.getsignal(signal.SIGINT)
signal.signal(signal.SIGINT, signal.SIG_IGN)
try:
print('Now ignoring CTRL-C')
yield
except:
raise # Exception is dropped if we don't reraise it.
finally:
print('Returning control to default signal handler')
signal.signal(signal.SIGINT, original_sigint_handler)
你可以像这样使用它:
# marker 1
print('No signal handler modifications yet')
print('Sleeping...')
time.sleep(10)
# marker 2
with sigint_ignored():
print('Sleeping...')
time.sleep(10)
# marker 3
print('Sleeping...')
time.sleep(10)