Will Python execute finally block after receiving Ctrl+C
Asked Answered
C

4

14

If you stop a python script with Ctrl+C, will it execute any finally blocks, or will it literally stop the script where it is?

Cavalry answered 22/12, 2016 at 9:56 Comment(3)
It kills it where it isBrookins
I do not understand what your question is meaning. I suggest you to read: stackoverflow.com/help/how-to-ask and catb.org/~esr/faqs/smart-questions.htmlStopgap
run CTRL+C from MinGW / Windows it just kills the process, doesn't send any keyboard interrupt. But that's a special case.Wrath
V
29

Well, the answer is mostly it depends. Here is what actually happens:

  • Python executes code in a try:... finally: block
  • a Ctrl-C is emitted and is translated in a KeyboardInterrupt Exception
  • processing is interrupted and controls passes to the finally block

So at first sight, all works as expected. But...

When a user (not you, but others...) wants to interrupt a task he generally hits multiple times Ctrl-C. The first one will branch execution in the finally block. If another Ctrl-C occurs in the middle of the finally block because it contains slow operations like closing files, a new KeyboardInterrupt will be raised and nothing guarantees that the whole block will be executed, and you could have something like:

Traceback (most recent call last):
  File "...", line ..., in ...
    ...
KeyboardInterrupt

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "...", line ..., in ...
    ...
  File "...", line ..., in ...
    ...
KeyboardInterrupt
Viable answered 8/3, 2017 at 14:56 Comment(3)
So how do we handle this case?Skilling
with statements and context managers perhaps? docs.python.org/3/library/contextlib.html. Or does the same issue apply?Decagram
Interestingly the documentation of signal gives an example where the cleanup doesn't happen as expected. The example is based on a context manager, not a plain finally block though. I would have expected the same behavior for a __exit__ of a context manager and a finally block, but perhaps there is a difference? My take on the docs is that even for the first KeyboardInterrupt the execution of finally isn't guaranteed (but likely). Did you use a different reference for that?Dogear
K
10

Yes, assuming a single Ctrl+C, at least under Linux it will. You can test it with the following Python 3 code:

import time

try:
    print('In try.')
    time.sleep(1000)
finally:
    print('  <-- Note the Ctrl+C.')
    for i in range(1, 6):
        print(f'Finishing up part {i} of 5.')
        time.sleep(.1)

Here is the output:

$ ./finally.py
In try.
^C  <-- Note the Ctrl+C.
Finishing up part 1 of 5.
Finishing up part 2 of 5.
Finishing up part 3 of 5.
Finishing up part 4 of 5.
Finishing up part 5 of 5.
Traceback (most recent call last):
  File "./finally.py", line 7, in <module>
    time.sleep(1000)
KeyboardInterrupt
Kacerek answered 22/12, 2016 at 20:43 Comment(0)
A
1

Yes, it will usually raise a KeyboardInterrupt exception, but remember that your application can be unexpectedly terminated at any time, so you shouldn't rely on that.

Agc answered 22/12, 2016 at 10:0 Comment(0)
C
1

By default, finally blocks will run following ctrl-c, as per other answers. However, if someone has overridden the default Python behaviour in an attempt to "avoid ugly KeyboardInterrupt tracebacks", then finally blocks will not run.

The way I've seen this done is with signal.signal(signal.SIGINT, signal.SIG_DFL). That will cause the application to exit immediately without any cleanup as soon as an interrupt is detected. As far as I can tell, this signal handler doesn't even bother to raise a KeyboardInterrupt. The standard behaviour can be restored by removing the above line or by adding signal.signal(signal.SIGINT, signal.default_int_handler).

Compatible answered 17/11, 2023 at 17:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.