Does 'finally' always execute in Python?
For any possible try-finally block in Python, is it guaranteed that the finally
block will always be executed?
For example, let’s say I return while in an except
block:
try:
1/0
except ZeroDivisionError:
return
finally:
print("Does this code run?")
Or maybe I re-raise an Exception
:
try:
1/0
except ZeroDivisionError:
raise
finally:
print("What about this code?")
Testing shows that finally
does get executed for the above examples, but I imagine there are other scenarios I haven't thought of.
Are there any scenarios in which a finally
block can fail to execute in Python?
python exception-handling try-catch-finally finally
|
show 1 more comment
For any possible try-finally block in Python, is it guaranteed that the finally
block will always be executed?
For example, let’s say I return while in an except
block:
try:
1/0
except ZeroDivisionError:
return
finally:
print("Does this code run?")
Or maybe I re-raise an Exception
:
try:
1/0
except ZeroDivisionError:
raise
finally:
print("What about this code?")
Testing shows that finally
does get executed for the above examples, but I imagine there are other scenarios I haven't thought of.
Are there any scenarios in which a finally
block can fail to execute in Python?
python exception-handling try-catch-finally finally
14
The only case I can imaginefinally
fail to execute or "defeat its purpose" is during an infinite loop,sys.exit
or a forced interrupt. The documentation states thatfinally
is always executed, so I'd go with that.
– Xay
Mar 13 '18 at 17:40
1
A bit of lateral thinking and sure not what you asked, but I'm pretty sure that if you open Task Manager and kill the process,finally
will not run. Or the same if the computer crashes before :D
– Alejandro
Mar 13 '18 at 19:18
120
finally
will not execute if the power cord is ripped from the wall.
– immibis
Mar 13 '18 at 20:33
3
You might be interested in this answer to the same question about C#: stackoverflow.com/a/10260233/88656
– Eric Lippert
Mar 14 '18 at 14:40
1
Block it on an empty semaphore. Never signal it. Done.
– Martin James
Mar 14 '18 at 19:56
|
show 1 more comment
For any possible try-finally block in Python, is it guaranteed that the finally
block will always be executed?
For example, let’s say I return while in an except
block:
try:
1/0
except ZeroDivisionError:
return
finally:
print("Does this code run?")
Or maybe I re-raise an Exception
:
try:
1/0
except ZeroDivisionError:
raise
finally:
print("What about this code?")
Testing shows that finally
does get executed for the above examples, but I imagine there are other scenarios I haven't thought of.
Are there any scenarios in which a finally
block can fail to execute in Python?
python exception-handling try-catch-finally finally
For any possible try-finally block in Python, is it guaranteed that the finally
block will always be executed?
For example, let’s say I return while in an except
block:
try:
1/0
except ZeroDivisionError:
return
finally:
print("Does this code run?")
Or maybe I re-raise an Exception
:
try:
1/0
except ZeroDivisionError:
raise
finally:
print("What about this code?")
Testing shows that finally
does get executed for the above examples, but I imagine there are other scenarios I haven't thought of.
Are there any scenarios in which a finally
block can fail to execute in Python?
python exception-handling try-catch-finally finally
python exception-handling try-catch-finally finally
edited Jul 20 '18 at 14:11
Steven M. Vascellaro
asked Mar 13 '18 at 17:30
Steven M. VascellaroSteven M. Vascellaro
5,69994291
5,69994291
14
The only case I can imaginefinally
fail to execute or "defeat its purpose" is during an infinite loop,sys.exit
or a forced interrupt. The documentation states thatfinally
is always executed, so I'd go with that.
– Xay
Mar 13 '18 at 17:40
1
A bit of lateral thinking and sure not what you asked, but I'm pretty sure that if you open Task Manager and kill the process,finally
will not run. Or the same if the computer crashes before :D
– Alejandro
Mar 13 '18 at 19:18
120
finally
will not execute if the power cord is ripped from the wall.
– immibis
Mar 13 '18 at 20:33
3
You might be interested in this answer to the same question about C#: stackoverflow.com/a/10260233/88656
– Eric Lippert
Mar 14 '18 at 14:40
1
Block it on an empty semaphore. Never signal it. Done.
– Martin James
Mar 14 '18 at 19:56
|
show 1 more comment
14
The only case I can imaginefinally
fail to execute or "defeat its purpose" is during an infinite loop,sys.exit
or a forced interrupt. The documentation states thatfinally
is always executed, so I'd go with that.
– Xay
Mar 13 '18 at 17:40
1
A bit of lateral thinking and sure not what you asked, but I'm pretty sure that if you open Task Manager and kill the process,finally
will not run. Or the same if the computer crashes before :D
– Alejandro
Mar 13 '18 at 19:18
120
finally
will not execute if the power cord is ripped from the wall.
– immibis
Mar 13 '18 at 20:33
3
You might be interested in this answer to the same question about C#: stackoverflow.com/a/10260233/88656
– Eric Lippert
Mar 14 '18 at 14:40
1
Block it on an empty semaphore. Never signal it. Done.
– Martin James
Mar 14 '18 at 19:56
14
14
The only case I can imagine
finally
fail to execute or "defeat its purpose" is during an infinite loop, sys.exit
or a forced interrupt. The documentation states that finally
is always executed, so I'd go with that.– Xay
Mar 13 '18 at 17:40
The only case I can imagine
finally
fail to execute or "defeat its purpose" is during an infinite loop, sys.exit
or a forced interrupt. The documentation states that finally
is always executed, so I'd go with that.– Xay
Mar 13 '18 at 17:40
1
1
A bit of lateral thinking and sure not what you asked, but I'm pretty sure that if you open Task Manager and kill the process,
finally
will not run. Or the same if the computer crashes before :D– Alejandro
Mar 13 '18 at 19:18
A bit of lateral thinking and sure not what you asked, but I'm pretty sure that if you open Task Manager and kill the process,
finally
will not run. Or the same if the computer crashes before :D– Alejandro
Mar 13 '18 at 19:18
120
120
finally
will not execute if the power cord is ripped from the wall.– immibis
Mar 13 '18 at 20:33
finally
will not execute if the power cord is ripped from the wall.– immibis
Mar 13 '18 at 20:33
3
3
You might be interested in this answer to the same question about C#: stackoverflow.com/a/10260233/88656
– Eric Lippert
Mar 14 '18 at 14:40
You might be interested in this answer to the same question about C#: stackoverflow.com/a/10260233/88656
– Eric Lippert
Mar 14 '18 at 14:40
1
1
Block it on an empty semaphore. Never signal it. Done.
– Martin James
Mar 14 '18 at 19:56
Block it on an empty semaphore. Never signal it. Done.
– Martin James
Mar 14 '18 at 19:56
|
show 1 more comment
5 Answers
5
active
oldest
votes
"Guaranteed" is a much stronger word than any implementation of finally
deserves. What is guaranteed is that if execution flows out of the whole try
-finally
construct, it will pass through the finally
to do so. What is not guaranteed is that execution will flow out of the try
-finally
.
A
finally
in a generator or async coroutine might never run, if the object never executes to conclusion. There are a lot of ways that could happen; here's one:
def gen(text):
try:
for line in text:
try:
yield int(line)
except:
# Ignore blank lines - but catch too much!
pass
finally:
print('Doing important cleanup')
text = ['1', '', '2', '', '3']
if any(n > 1 for n in gen(text)):
print('Found a number')
print('Oops, no cleanup.')
Note that this example is a bit tricky: when the generator is garbage collected, Python attempts to run the
finally
block by throwing in aGeneratorExit
exception, but here we catch that exception and thenyield
again, at which point Python prints a warning ("generator ignored GeneratorExit") and gives up. See PEP 342 (Coroutines via Enhanced Generators) for details.
Other ways a generator or coroutine might not execute to conclusion include if the object is just never GC'ed (yes, that's possible, even in CPython), or if an
async with
await
s in__aexit__
, or if the objectawait
s oryield
s in afinally
block. This list is not intended to be exhaustive.
A
finally
in a daemon thread might never execute if all non-daemon threads exit first.os._exit
will halt the process immediately without executingfinally
blocks.
os.fork
may causefinally
blocks to execute twice. As well as just the normal problems you'd expect from things happening twice, this could cause concurrent access conflicts (crashes, stalls, ...) if access to shared resources is not correctly synchronized.
Since
multiprocessing
uses fork-without-exec to create worker processes when using the fork start method (the default on Unix), and then callsos._exit
in the worker once the worker's job is done,finally
andmultiprocessing
interaction can be problematic (example).
- A C-level segmentation fault will prevent
finally
blocks from running.
kill -SIGKILL
will preventfinally
blocks from running.SIGTERM
andSIGHUP
will also preventfinally
blocks from running unless you install a handler to control the shutdown yourself; by default, Python does not handleSIGTERM
orSIGHUP
.- An exception in
finally
can prevent cleanup from completing. One particularly noteworthy case is if the user hits control-C just as we're starting to execute thefinally
block. Python will raise aKeyboardInterrupt
and skip every line of thefinally
block's contents. (KeyboardInterrupt
-safe code is very hard to write). - If the computer loses power, or if it hibernates and doesn't wake up,
finally
blocks won't run.
The finally
block is not a transaction system; it doesn't provide atomicity guarantees or anything of the sort. Some of these examples might seem obvious, but it's easy to forget such things can happen and rely on finally
for too much.
13
I believe only the first point of your list is really relevant, and there is an easy way to avoid it: 1) never use a bareexcept
, and never catchGeneratorExit
inside a generator. The points about threads/killing the process/segfaulting/power off are expected, python can't do magic. Also: exceptions infinally
are obviously a problem but this does not change the fact that the control flow was moved to thefinally
block. RegardingCtrl+C
, you can add a signal handler that ignores it, or simply "schedules" a clean shutdown after the current operation is completed.
– Giacomo Alzetta
Mar 14 '18 at 8:27
8
The mentioning of kill -9 is technically correct, but a bit unfair. No program written in any language runs any code upon receiving a kill -9. In fact, no program ever receives a kill -9 at all, so even if it wanted to, it couldn't execute anything. That's the whole point of kill -9.
– Tom
Mar 14 '18 at 14:02
10
@Tom: The point aboutkill -9
didn't specify a language. And frankly, it needs repeating, because it sits in a blind spot. Too many people forget, or don't realize, that their program could be stopped dead in its tracks without even being allowed to clean up.
– cHao
Mar 14 '18 at 14:39
4
@GiacomoAlzetta: There are people out there relying onfinally
blocks as if they provided transactional guarantees. It might seem obvious that they don't, but it's not something everyone realizes. As for the generator case, there are a lot of ways a generator might not be GC'ed at all, and a lot of ways a generator or coroutine might accidentally yield afterGeneratorExit
even if it doesn't catch theGeneratorExit
, for example if anasync with
suspends a coroutine in__exit__
.
– user2357112
Mar 14 '18 at 16:52
2
@user2357112 yeah - I've been trying for decades to get devs to clean up temp files etc. on app startup, not exit. Relying on the so-called 'clean up and graceful termination', is asking for disappointment and tears:)
– Martin James
Mar 14 '18 at 19:52
|
show 1 more comment
Yes. Finally always wins.
The only way to defeat it is to halt execution before finally:
gets a chance to execute (e.g. crash the interpreter, turn off your computer, suspend a generator forever).
I imagine there are other scenarios I haven't thought of.
Here are a couple more you may not have thought about:
def foo():
# finally always wins
try:
return 1
finally:
return 2
def bar():
# even if he has to eat an unhandled exception, finally wins
try:
raise Exception('boom')
finally:
return 'no boom'
Depending on how you quit the interpreter, sometimes you can "cancel" finally, but not like this:
>>> import sys
>>> try:
... sys.exit()
... finally:
... print('finally wins!')
...
finally wins!
$
Using the precarious os._exit
(this falls under "crash the interpreter" in my opinion):
>>> import os
>>> try:
... os._exit(1)
... finally:
... print('finally!')
...
$
I'm currently running this code, to test if finally will still execute after the heat death of the universe:
try:
while True:
sleep(1)
finally:
print('done')
However, I'm still waiting on the result, so check back here later.
5
or having an i finite loop in try catch
– sapy
Mar 13 '18 at 17:48
8
finally
in a generator or coroutine can quite easily fail to execute, without going anywhere near a "crash the interpreter" condition.
– user2357112
Mar 13 '18 at 19:00
22
After the heat death of the universe time ceases to exist, sosleep(1)
would definitely result in undefined behaviour. :-D
– David Foerster
Mar 13 '18 at 19:19
You may want to mention _os.exit directly after “the only way to defeat it is to crash the compiler”. Right now it’s mixed inbeteween examples where finally wins.
– Steven M. Vascellaro
Mar 13 '18 at 21:45
2
@StevenVascellaro I don't think that's necessary -os._exit
is, for all practical purposes, the same as inducing a crash (unclean exit). The correct way to exit issys.exit
.
– wim
Mar 13 '18 at 22:58
|
show 1 more comment
According to the Python documentation:
No matter what happened previously, the final-block is executed once the code block is complete and any raised exceptions handled. Even if there's an error in an exception handler or the else-block and a new exception is raised, the code in the final-block is still run.
It should also be noted that if there are multiple return statements, including one in the finally block, then the finally block return is the only one that will execute.
add a comment |
Well, yes and no.
What is guaranteed is that Python will always try to execute the finally block. In the case where you return from the block or raise an uncaught exception, the finally block is executed just before actually returning or raising the exception.
(what you could have controlled yourself by simply running the code in your question)
The only case I can imagine where the finally block will not be executed is when the Python interpretor itself crashes for example inside C code or because of power outage.
ha ha .. or there is a infinite loop in try catch
– sapy
Mar 13 '18 at 17:46
2
Is it uncatched or uncaught?
– Stan Strum
Mar 13 '18 at 20:53
@StanStrum: Fixed. Sorry for the mistake, but English is not my first language...
– Serge Ballesta
Mar 14 '18 at 7:38
@SergeBallesta No biggie. At least here in rural UK plenty of people say "catched". Natives too.
– Wilson
Mar 14 '18 at 13:58
I think "Well, yes and no" is most correct. Finally: always wins where "always" means the interpreter is able to run and the code for the "finally:" is still available, and "wins" is defined as the interpreter will try to run the finally: block and it will succeed. That's the "Yes" and it is very conditional. "No" is all the ways the interpreter might stop before "finally:"- power failure, hardware failure, kill -9 aimed at the interpreter, errors in the interpreter or code it depends on, other ways to hang the interpreter. And ways to hang inside the "finally:".
– Bill IV
Mar 15 '18 at 0:25
add a comment |
To really understand how it works, just run these two examples:
try:
1
except:
print 'except'
finally:
print 'finally'
will output
finally
try:
1/0
except:
print 'except'
finally:
print 'finally'
will output
except
finally
add a comment |
protected by heemayl Mar 14 '18 at 18:15
Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).
Would you like to answer one of these unanswered questions instead?
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
"Guaranteed" is a much stronger word than any implementation of finally
deserves. What is guaranteed is that if execution flows out of the whole try
-finally
construct, it will pass through the finally
to do so. What is not guaranteed is that execution will flow out of the try
-finally
.
A
finally
in a generator or async coroutine might never run, if the object never executes to conclusion. There are a lot of ways that could happen; here's one:
def gen(text):
try:
for line in text:
try:
yield int(line)
except:
# Ignore blank lines - but catch too much!
pass
finally:
print('Doing important cleanup')
text = ['1', '', '2', '', '3']
if any(n > 1 for n in gen(text)):
print('Found a number')
print('Oops, no cleanup.')
Note that this example is a bit tricky: when the generator is garbage collected, Python attempts to run the
finally
block by throwing in aGeneratorExit
exception, but here we catch that exception and thenyield
again, at which point Python prints a warning ("generator ignored GeneratorExit") and gives up. See PEP 342 (Coroutines via Enhanced Generators) for details.
Other ways a generator or coroutine might not execute to conclusion include if the object is just never GC'ed (yes, that's possible, even in CPython), or if an
async with
await
s in__aexit__
, or if the objectawait
s oryield
s in afinally
block. This list is not intended to be exhaustive.
A
finally
in a daemon thread might never execute if all non-daemon threads exit first.os._exit
will halt the process immediately without executingfinally
blocks.
os.fork
may causefinally
blocks to execute twice. As well as just the normal problems you'd expect from things happening twice, this could cause concurrent access conflicts (crashes, stalls, ...) if access to shared resources is not correctly synchronized.
Since
multiprocessing
uses fork-without-exec to create worker processes when using the fork start method (the default on Unix), and then callsos._exit
in the worker once the worker's job is done,finally
andmultiprocessing
interaction can be problematic (example).
- A C-level segmentation fault will prevent
finally
blocks from running.
kill -SIGKILL
will preventfinally
blocks from running.SIGTERM
andSIGHUP
will also preventfinally
blocks from running unless you install a handler to control the shutdown yourself; by default, Python does not handleSIGTERM
orSIGHUP
.- An exception in
finally
can prevent cleanup from completing. One particularly noteworthy case is if the user hits control-C just as we're starting to execute thefinally
block. Python will raise aKeyboardInterrupt
and skip every line of thefinally
block's contents. (KeyboardInterrupt
-safe code is very hard to write). - If the computer loses power, or if it hibernates and doesn't wake up,
finally
blocks won't run.
The finally
block is not a transaction system; it doesn't provide atomicity guarantees or anything of the sort. Some of these examples might seem obvious, but it's easy to forget such things can happen and rely on finally
for too much.
13
I believe only the first point of your list is really relevant, and there is an easy way to avoid it: 1) never use a bareexcept
, and never catchGeneratorExit
inside a generator. The points about threads/killing the process/segfaulting/power off are expected, python can't do magic. Also: exceptions infinally
are obviously a problem but this does not change the fact that the control flow was moved to thefinally
block. RegardingCtrl+C
, you can add a signal handler that ignores it, or simply "schedules" a clean shutdown after the current operation is completed.
– Giacomo Alzetta
Mar 14 '18 at 8:27
8
The mentioning of kill -9 is technically correct, but a bit unfair. No program written in any language runs any code upon receiving a kill -9. In fact, no program ever receives a kill -9 at all, so even if it wanted to, it couldn't execute anything. That's the whole point of kill -9.
– Tom
Mar 14 '18 at 14:02
10
@Tom: The point aboutkill -9
didn't specify a language. And frankly, it needs repeating, because it sits in a blind spot. Too many people forget, or don't realize, that their program could be stopped dead in its tracks without even being allowed to clean up.
– cHao
Mar 14 '18 at 14:39
4
@GiacomoAlzetta: There are people out there relying onfinally
blocks as if they provided transactional guarantees. It might seem obvious that they don't, but it's not something everyone realizes. As for the generator case, there are a lot of ways a generator might not be GC'ed at all, and a lot of ways a generator or coroutine might accidentally yield afterGeneratorExit
even if it doesn't catch theGeneratorExit
, for example if anasync with
suspends a coroutine in__exit__
.
– user2357112
Mar 14 '18 at 16:52
2
@user2357112 yeah - I've been trying for decades to get devs to clean up temp files etc. on app startup, not exit. Relying on the so-called 'clean up and graceful termination', is asking for disappointment and tears:)
– Martin James
Mar 14 '18 at 19:52
|
show 1 more comment
"Guaranteed" is a much stronger word than any implementation of finally
deserves. What is guaranteed is that if execution flows out of the whole try
-finally
construct, it will pass through the finally
to do so. What is not guaranteed is that execution will flow out of the try
-finally
.
A
finally
in a generator or async coroutine might never run, if the object never executes to conclusion. There are a lot of ways that could happen; here's one:
def gen(text):
try:
for line in text:
try:
yield int(line)
except:
# Ignore blank lines - but catch too much!
pass
finally:
print('Doing important cleanup')
text = ['1', '', '2', '', '3']
if any(n > 1 for n in gen(text)):
print('Found a number')
print('Oops, no cleanup.')
Note that this example is a bit tricky: when the generator is garbage collected, Python attempts to run the
finally
block by throwing in aGeneratorExit
exception, but here we catch that exception and thenyield
again, at which point Python prints a warning ("generator ignored GeneratorExit") and gives up. See PEP 342 (Coroutines via Enhanced Generators) for details.
Other ways a generator or coroutine might not execute to conclusion include if the object is just never GC'ed (yes, that's possible, even in CPython), or if an
async with
await
s in__aexit__
, or if the objectawait
s oryield
s in afinally
block. This list is not intended to be exhaustive.
A
finally
in a daemon thread might never execute if all non-daemon threads exit first.os._exit
will halt the process immediately without executingfinally
blocks.
os.fork
may causefinally
blocks to execute twice. As well as just the normal problems you'd expect from things happening twice, this could cause concurrent access conflicts (crashes, stalls, ...) if access to shared resources is not correctly synchronized.
Since
multiprocessing
uses fork-without-exec to create worker processes when using the fork start method (the default on Unix), and then callsos._exit
in the worker once the worker's job is done,finally
andmultiprocessing
interaction can be problematic (example).
- A C-level segmentation fault will prevent
finally
blocks from running.
kill -SIGKILL
will preventfinally
blocks from running.SIGTERM
andSIGHUP
will also preventfinally
blocks from running unless you install a handler to control the shutdown yourself; by default, Python does not handleSIGTERM
orSIGHUP
.- An exception in
finally
can prevent cleanup from completing. One particularly noteworthy case is if the user hits control-C just as we're starting to execute thefinally
block. Python will raise aKeyboardInterrupt
and skip every line of thefinally
block's contents. (KeyboardInterrupt
-safe code is very hard to write). - If the computer loses power, or if it hibernates and doesn't wake up,
finally
blocks won't run.
The finally
block is not a transaction system; it doesn't provide atomicity guarantees or anything of the sort. Some of these examples might seem obvious, but it's easy to forget such things can happen and rely on finally
for too much.
13
I believe only the first point of your list is really relevant, and there is an easy way to avoid it: 1) never use a bareexcept
, and never catchGeneratorExit
inside a generator. The points about threads/killing the process/segfaulting/power off are expected, python can't do magic. Also: exceptions infinally
are obviously a problem but this does not change the fact that the control flow was moved to thefinally
block. RegardingCtrl+C
, you can add a signal handler that ignores it, or simply "schedules" a clean shutdown after the current operation is completed.
– Giacomo Alzetta
Mar 14 '18 at 8:27
8
The mentioning of kill -9 is technically correct, but a bit unfair. No program written in any language runs any code upon receiving a kill -9. In fact, no program ever receives a kill -9 at all, so even if it wanted to, it couldn't execute anything. That's the whole point of kill -9.
– Tom
Mar 14 '18 at 14:02
10
@Tom: The point aboutkill -9
didn't specify a language. And frankly, it needs repeating, because it sits in a blind spot. Too many people forget, or don't realize, that their program could be stopped dead in its tracks without even being allowed to clean up.
– cHao
Mar 14 '18 at 14:39
4
@GiacomoAlzetta: There are people out there relying onfinally
blocks as if they provided transactional guarantees. It might seem obvious that they don't, but it's not something everyone realizes. As for the generator case, there are a lot of ways a generator might not be GC'ed at all, and a lot of ways a generator or coroutine might accidentally yield afterGeneratorExit
even if it doesn't catch theGeneratorExit
, for example if anasync with
suspends a coroutine in__exit__
.
– user2357112
Mar 14 '18 at 16:52
2
@user2357112 yeah - I've been trying for decades to get devs to clean up temp files etc. on app startup, not exit. Relying on the so-called 'clean up and graceful termination', is asking for disappointment and tears:)
– Martin James
Mar 14 '18 at 19:52
|
show 1 more comment
"Guaranteed" is a much stronger word than any implementation of finally
deserves. What is guaranteed is that if execution flows out of the whole try
-finally
construct, it will pass through the finally
to do so. What is not guaranteed is that execution will flow out of the try
-finally
.
A
finally
in a generator or async coroutine might never run, if the object never executes to conclusion. There are a lot of ways that could happen; here's one:
def gen(text):
try:
for line in text:
try:
yield int(line)
except:
# Ignore blank lines - but catch too much!
pass
finally:
print('Doing important cleanup')
text = ['1', '', '2', '', '3']
if any(n > 1 for n in gen(text)):
print('Found a number')
print('Oops, no cleanup.')
Note that this example is a bit tricky: when the generator is garbage collected, Python attempts to run the
finally
block by throwing in aGeneratorExit
exception, but here we catch that exception and thenyield
again, at which point Python prints a warning ("generator ignored GeneratorExit") and gives up. See PEP 342 (Coroutines via Enhanced Generators) for details.
Other ways a generator or coroutine might not execute to conclusion include if the object is just never GC'ed (yes, that's possible, even in CPython), or if an
async with
await
s in__aexit__
, or if the objectawait
s oryield
s in afinally
block. This list is not intended to be exhaustive.
A
finally
in a daemon thread might never execute if all non-daemon threads exit first.os._exit
will halt the process immediately without executingfinally
blocks.
os.fork
may causefinally
blocks to execute twice. As well as just the normal problems you'd expect from things happening twice, this could cause concurrent access conflicts (crashes, stalls, ...) if access to shared resources is not correctly synchronized.
Since
multiprocessing
uses fork-without-exec to create worker processes when using the fork start method (the default on Unix), and then callsos._exit
in the worker once the worker's job is done,finally
andmultiprocessing
interaction can be problematic (example).
- A C-level segmentation fault will prevent
finally
blocks from running.
kill -SIGKILL
will preventfinally
blocks from running.SIGTERM
andSIGHUP
will also preventfinally
blocks from running unless you install a handler to control the shutdown yourself; by default, Python does not handleSIGTERM
orSIGHUP
.- An exception in
finally
can prevent cleanup from completing. One particularly noteworthy case is if the user hits control-C just as we're starting to execute thefinally
block. Python will raise aKeyboardInterrupt
and skip every line of thefinally
block's contents. (KeyboardInterrupt
-safe code is very hard to write). - If the computer loses power, or if it hibernates and doesn't wake up,
finally
blocks won't run.
The finally
block is not a transaction system; it doesn't provide atomicity guarantees or anything of the sort. Some of these examples might seem obvious, but it's easy to forget such things can happen and rely on finally
for too much.
"Guaranteed" is a much stronger word than any implementation of finally
deserves. What is guaranteed is that if execution flows out of the whole try
-finally
construct, it will pass through the finally
to do so. What is not guaranteed is that execution will flow out of the try
-finally
.
A
finally
in a generator or async coroutine might never run, if the object never executes to conclusion. There are a lot of ways that could happen; here's one:
def gen(text):
try:
for line in text:
try:
yield int(line)
except:
# Ignore blank lines - but catch too much!
pass
finally:
print('Doing important cleanup')
text = ['1', '', '2', '', '3']
if any(n > 1 for n in gen(text)):
print('Found a number')
print('Oops, no cleanup.')
Note that this example is a bit tricky: when the generator is garbage collected, Python attempts to run the
finally
block by throwing in aGeneratorExit
exception, but here we catch that exception and thenyield
again, at which point Python prints a warning ("generator ignored GeneratorExit") and gives up. See PEP 342 (Coroutines via Enhanced Generators) for details.
Other ways a generator or coroutine might not execute to conclusion include if the object is just never GC'ed (yes, that's possible, even in CPython), or if an
async with
await
s in__aexit__
, or if the objectawait
s oryield
s in afinally
block. This list is not intended to be exhaustive.
A
finally
in a daemon thread might never execute if all non-daemon threads exit first.os._exit
will halt the process immediately without executingfinally
blocks.
os.fork
may causefinally
blocks to execute twice. As well as just the normal problems you'd expect from things happening twice, this could cause concurrent access conflicts (crashes, stalls, ...) if access to shared resources is not correctly synchronized.
Since
multiprocessing
uses fork-without-exec to create worker processes when using the fork start method (the default on Unix), and then callsos._exit
in the worker once the worker's job is done,finally
andmultiprocessing
interaction can be problematic (example).
- A C-level segmentation fault will prevent
finally
blocks from running.
kill -SIGKILL
will preventfinally
blocks from running.SIGTERM
andSIGHUP
will also preventfinally
blocks from running unless you install a handler to control the shutdown yourself; by default, Python does not handleSIGTERM
orSIGHUP
.- An exception in
finally
can prevent cleanup from completing. One particularly noteworthy case is if the user hits control-C just as we're starting to execute thefinally
block. Python will raise aKeyboardInterrupt
and skip every line of thefinally
block's contents. (KeyboardInterrupt
-safe code is very hard to write). - If the computer loses power, or if it hibernates and doesn't wake up,
finally
blocks won't run.
The finally
block is not a transaction system; it doesn't provide atomicity guarantees or anything of the sort. Some of these examples might seem obvious, but it's easy to forget such things can happen and rely on finally
for too much.
edited Mar 29 '18 at 16:54
answered Mar 13 '18 at 17:48
user2357112user2357112
156k12168263
156k12168263
13
I believe only the first point of your list is really relevant, and there is an easy way to avoid it: 1) never use a bareexcept
, and never catchGeneratorExit
inside a generator. The points about threads/killing the process/segfaulting/power off are expected, python can't do magic. Also: exceptions infinally
are obviously a problem but this does not change the fact that the control flow was moved to thefinally
block. RegardingCtrl+C
, you can add a signal handler that ignores it, or simply "schedules" a clean shutdown after the current operation is completed.
– Giacomo Alzetta
Mar 14 '18 at 8:27
8
The mentioning of kill -9 is technically correct, but a bit unfair. No program written in any language runs any code upon receiving a kill -9. In fact, no program ever receives a kill -9 at all, so even if it wanted to, it couldn't execute anything. That's the whole point of kill -9.
– Tom
Mar 14 '18 at 14:02
10
@Tom: The point aboutkill -9
didn't specify a language. And frankly, it needs repeating, because it sits in a blind spot. Too many people forget, or don't realize, that their program could be stopped dead in its tracks without even being allowed to clean up.
– cHao
Mar 14 '18 at 14:39
4
@GiacomoAlzetta: There are people out there relying onfinally
blocks as if they provided transactional guarantees. It might seem obvious that they don't, but it's not something everyone realizes. As for the generator case, there are a lot of ways a generator might not be GC'ed at all, and a lot of ways a generator or coroutine might accidentally yield afterGeneratorExit
even if it doesn't catch theGeneratorExit
, for example if anasync with
suspends a coroutine in__exit__
.
– user2357112
Mar 14 '18 at 16:52
2
@user2357112 yeah - I've been trying for decades to get devs to clean up temp files etc. on app startup, not exit. Relying on the so-called 'clean up and graceful termination', is asking for disappointment and tears:)
– Martin James
Mar 14 '18 at 19:52
|
show 1 more comment
13
I believe only the first point of your list is really relevant, and there is an easy way to avoid it: 1) never use a bareexcept
, and never catchGeneratorExit
inside a generator. The points about threads/killing the process/segfaulting/power off are expected, python can't do magic. Also: exceptions infinally
are obviously a problem but this does not change the fact that the control flow was moved to thefinally
block. RegardingCtrl+C
, you can add a signal handler that ignores it, or simply "schedules" a clean shutdown after the current operation is completed.
– Giacomo Alzetta
Mar 14 '18 at 8:27
8
The mentioning of kill -9 is technically correct, but a bit unfair. No program written in any language runs any code upon receiving a kill -9. In fact, no program ever receives a kill -9 at all, so even if it wanted to, it couldn't execute anything. That's the whole point of kill -9.
– Tom
Mar 14 '18 at 14:02
10
@Tom: The point aboutkill -9
didn't specify a language. And frankly, it needs repeating, because it sits in a blind spot. Too many people forget, or don't realize, that their program could be stopped dead in its tracks without even being allowed to clean up.
– cHao
Mar 14 '18 at 14:39
4
@GiacomoAlzetta: There are people out there relying onfinally
blocks as if they provided transactional guarantees. It might seem obvious that they don't, but it's not something everyone realizes. As for the generator case, there are a lot of ways a generator might not be GC'ed at all, and a lot of ways a generator or coroutine might accidentally yield afterGeneratorExit
even if it doesn't catch theGeneratorExit
, for example if anasync with
suspends a coroutine in__exit__
.
– user2357112
Mar 14 '18 at 16:52
2
@user2357112 yeah - I've been trying for decades to get devs to clean up temp files etc. on app startup, not exit. Relying on the so-called 'clean up and graceful termination', is asking for disappointment and tears:)
– Martin James
Mar 14 '18 at 19:52
13
13
I believe only the first point of your list is really relevant, and there is an easy way to avoid it: 1) never use a bare
except
, and never catch GeneratorExit
inside a generator. The points about threads/killing the process/segfaulting/power off are expected, python can't do magic. Also: exceptions in finally
are obviously a problem but this does not change the fact that the control flow was moved to the finally
block. Regarding Ctrl+C
, you can add a signal handler that ignores it, or simply "schedules" a clean shutdown after the current operation is completed.– Giacomo Alzetta
Mar 14 '18 at 8:27
I believe only the first point of your list is really relevant, and there is an easy way to avoid it: 1) never use a bare
except
, and never catch GeneratorExit
inside a generator. The points about threads/killing the process/segfaulting/power off are expected, python can't do magic. Also: exceptions in finally
are obviously a problem but this does not change the fact that the control flow was moved to the finally
block. Regarding Ctrl+C
, you can add a signal handler that ignores it, or simply "schedules" a clean shutdown after the current operation is completed.– Giacomo Alzetta
Mar 14 '18 at 8:27
8
8
The mentioning of kill -9 is technically correct, but a bit unfair. No program written in any language runs any code upon receiving a kill -9. In fact, no program ever receives a kill -9 at all, so even if it wanted to, it couldn't execute anything. That's the whole point of kill -9.
– Tom
Mar 14 '18 at 14:02
The mentioning of kill -9 is technically correct, but a bit unfair. No program written in any language runs any code upon receiving a kill -9. In fact, no program ever receives a kill -9 at all, so even if it wanted to, it couldn't execute anything. That's the whole point of kill -9.
– Tom
Mar 14 '18 at 14:02
10
10
@Tom: The point about
kill -9
didn't specify a language. And frankly, it needs repeating, because it sits in a blind spot. Too many people forget, or don't realize, that their program could be stopped dead in its tracks without even being allowed to clean up.– cHao
Mar 14 '18 at 14:39
@Tom: The point about
kill -9
didn't specify a language. And frankly, it needs repeating, because it sits in a blind spot. Too many people forget, or don't realize, that their program could be stopped dead in its tracks without even being allowed to clean up.– cHao
Mar 14 '18 at 14:39
4
4
@GiacomoAlzetta: There are people out there relying on
finally
blocks as if they provided transactional guarantees. It might seem obvious that they don't, but it's not something everyone realizes. As for the generator case, there are a lot of ways a generator might not be GC'ed at all, and a lot of ways a generator or coroutine might accidentally yield after GeneratorExit
even if it doesn't catch the GeneratorExit
, for example if an async with
suspends a coroutine in __exit__
.– user2357112
Mar 14 '18 at 16:52
@GiacomoAlzetta: There are people out there relying on
finally
blocks as if they provided transactional guarantees. It might seem obvious that they don't, but it's not something everyone realizes. As for the generator case, there are a lot of ways a generator might not be GC'ed at all, and a lot of ways a generator or coroutine might accidentally yield after GeneratorExit
even if it doesn't catch the GeneratorExit
, for example if an async with
suspends a coroutine in __exit__
.– user2357112
Mar 14 '18 at 16:52
2
2
@user2357112 yeah - I've been trying for decades to get devs to clean up temp files etc. on app startup, not exit. Relying on the so-called 'clean up and graceful termination', is asking for disappointment and tears:)
– Martin James
Mar 14 '18 at 19:52
@user2357112 yeah - I've been trying for decades to get devs to clean up temp files etc. on app startup, not exit. Relying on the so-called 'clean up and graceful termination', is asking for disappointment and tears:)
– Martin James
Mar 14 '18 at 19:52
|
show 1 more comment
Yes. Finally always wins.
The only way to defeat it is to halt execution before finally:
gets a chance to execute (e.g. crash the interpreter, turn off your computer, suspend a generator forever).
I imagine there are other scenarios I haven't thought of.
Here are a couple more you may not have thought about:
def foo():
# finally always wins
try:
return 1
finally:
return 2
def bar():
# even if he has to eat an unhandled exception, finally wins
try:
raise Exception('boom')
finally:
return 'no boom'
Depending on how you quit the interpreter, sometimes you can "cancel" finally, but not like this:
>>> import sys
>>> try:
... sys.exit()
... finally:
... print('finally wins!')
...
finally wins!
$
Using the precarious os._exit
(this falls under "crash the interpreter" in my opinion):
>>> import os
>>> try:
... os._exit(1)
... finally:
... print('finally!')
...
$
I'm currently running this code, to test if finally will still execute after the heat death of the universe:
try:
while True:
sleep(1)
finally:
print('done')
However, I'm still waiting on the result, so check back here later.
5
or having an i finite loop in try catch
– sapy
Mar 13 '18 at 17:48
8
finally
in a generator or coroutine can quite easily fail to execute, without going anywhere near a "crash the interpreter" condition.
– user2357112
Mar 13 '18 at 19:00
22
After the heat death of the universe time ceases to exist, sosleep(1)
would definitely result in undefined behaviour. :-D
– David Foerster
Mar 13 '18 at 19:19
You may want to mention _os.exit directly after “the only way to defeat it is to crash the compiler”. Right now it’s mixed inbeteween examples where finally wins.
– Steven M. Vascellaro
Mar 13 '18 at 21:45
2
@StevenVascellaro I don't think that's necessary -os._exit
is, for all practical purposes, the same as inducing a crash (unclean exit). The correct way to exit issys.exit
.
– wim
Mar 13 '18 at 22:58
|
show 1 more comment
Yes. Finally always wins.
The only way to defeat it is to halt execution before finally:
gets a chance to execute (e.g. crash the interpreter, turn off your computer, suspend a generator forever).
I imagine there are other scenarios I haven't thought of.
Here are a couple more you may not have thought about:
def foo():
# finally always wins
try:
return 1
finally:
return 2
def bar():
# even if he has to eat an unhandled exception, finally wins
try:
raise Exception('boom')
finally:
return 'no boom'
Depending on how you quit the interpreter, sometimes you can "cancel" finally, but not like this:
>>> import sys
>>> try:
... sys.exit()
... finally:
... print('finally wins!')
...
finally wins!
$
Using the precarious os._exit
(this falls under "crash the interpreter" in my opinion):
>>> import os
>>> try:
... os._exit(1)
... finally:
... print('finally!')
...
$
I'm currently running this code, to test if finally will still execute after the heat death of the universe:
try:
while True:
sleep(1)
finally:
print('done')
However, I'm still waiting on the result, so check back here later.
5
or having an i finite loop in try catch
– sapy
Mar 13 '18 at 17:48
8
finally
in a generator or coroutine can quite easily fail to execute, without going anywhere near a "crash the interpreter" condition.
– user2357112
Mar 13 '18 at 19:00
22
After the heat death of the universe time ceases to exist, sosleep(1)
would definitely result in undefined behaviour. :-D
– David Foerster
Mar 13 '18 at 19:19
You may want to mention _os.exit directly after “the only way to defeat it is to crash the compiler”. Right now it’s mixed inbeteween examples where finally wins.
– Steven M. Vascellaro
Mar 13 '18 at 21:45
2
@StevenVascellaro I don't think that's necessary -os._exit
is, for all practical purposes, the same as inducing a crash (unclean exit). The correct way to exit issys.exit
.
– wim
Mar 13 '18 at 22:58
|
show 1 more comment
Yes. Finally always wins.
The only way to defeat it is to halt execution before finally:
gets a chance to execute (e.g. crash the interpreter, turn off your computer, suspend a generator forever).
I imagine there are other scenarios I haven't thought of.
Here are a couple more you may not have thought about:
def foo():
# finally always wins
try:
return 1
finally:
return 2
def bar():
# even if he has to eat an unhandled exception, finally wins
try:
raise Exception('boom')
finally:
return 'no boom'
Depending on how you quit the interpreter, sometimes you can "cancel" finally, but not like this:
>>> import sys
>>> try:
... sys.exit()
... finally:
... print('finally wins!')
...
finally wins!
$
Using the precarious os._exit
(this falls under "crash the interpreter" in my opinion):
>>> import os
>>> try:
... os._exit(1)
... finally:
... print('finally!')
...
$
I'm currently running this code, to test if finally will still execute after the heat death of the universe:
try:
while True:
sleep(1)
finally:
print('done')
However, I'm still waiting on the result, so check back here later.
Yes. Finally always wins.
The only way to defeat it is to halt execution before finally:
gets a chance to execute (e.g. crash the interpreter, turn off your computer, suspend a generator forever).
I imagine there are other scenarios I haven't thought of.
Here are a couple more you may not have thought about:
def foo():
# finally always wins
try:
return 1
finally:
return 2
def bar():
# even if he has to eat an unhandled exception, finally wins
try:
raise Exception('boom')
finally:
return 'no boom'
Depending on how you quit the interpreter, sometimes you can "cancel" finally, but not like this:
>>> import sys
>>> try:
... sys.exit()
... finally:
... print('finally wins!')
...
finally wins!
$
Using the precarious os._exit
(this falls under "crash the interpreter" in my opinion):
>>> import os
>>> try:
... os._exit(1)
... finally:
... print('finally!')
...
$
I'm currently running this code, to test if finally will still execute after the heat death of the universe:
try:
while True:
sleep(1)
finally:
print('done')
However, I'm still waiting on the result, so check back here later.
edited Sep 12 '18 at 6:18
answered Mar 13 '18 at 17:40
wimwim
164k51314446
164k51314446
5
or having an i finite loop in try catch
– sapy
Mar 13 '18 at 17:48
8
finally
in a generator or coroutine can quite easily fail to execute, without going anywhere near a "crash the interpreter" condition.
– user2357112
Mar 13 '18 at 19:00
22
After the heat death of the universe time ceases to exist, sosleep(1)
would definitely result in undefined behaviour. :-D
– David Foerster
Mar 13 '18 at 19:19
You may want to mention _os.exit directly after “the only way to defeat it is to crash the compiler”. Right now it’s mixed inbeteween examples where finally wins.
– Steven M. Vascellaro
Mar 13 '18 at 21:45
2
@StevenVascellaro I don't think that's necessary -os._exit
is, for all practical purposes, the same as inducing a crash (unclean exit). The correct way to exit issys.exit
.
– wim
Mar 13 '18 at 22:58
|
show 1 more comment
5
or having an i finite loop in try catch
– sapy
Mar 13 '18 at 17:48
8
finally
in a generator or coroutine can quite easily fail to execute, without going anywhere near a "crash the interpreter" condition.
– user2357112
Mar 13 '18 at 19:00
22
After the heat death of the universe time ceases to exist, sosleep(1)
would definitely result in undefined behaviour. :-D
– David Foerster
Mar 13 '18 at 19:19
You may want to mention _os.exit directly after “the only way to defeat it is to crash the compiler”. Right now it’s mixed inbeteween examples where finally wins.
– Steven M. Vascellaro
Mar 13 '18 at 21:45
2
@StevenVascellaro I don't think that's necessary -os._exit
is, for all practical purposes, the same as inducing a crash (unclean exit). The correct way to exit issys.exit
.
– wim
Mar 13 '18 at 22:58
5
5
or having an i finite loop in try catch
– sapy
Mar 13 '18 at 17:48
or having an i finite loop in try catch
– sapy
Mar 13 '18 at 17:48
8
8
finally
in a generator or coroutine can quite easily fail to execute, without going anywhere near a "crash the interpreter" condition.– user2357112
Mar 13 '18 at 19:00
finally
in a generator or coroutine can quite easily fail to execute, without going anywhere near a "crash the interpreter" condition.– user2357112
Mar 13 '18 at 19:00
22
22
After the heat death of the universe time ceases to exist, so
sleep(1)
would definitely result in undefined behaviour. :-D– David Foerster
Mar 13 '18 at 19:19
After the heat death of the universe time ceases to exist, so
sleep(1)
would definitely result in undefined behaviour. :-D– David Foerster
Mar 13 '18 at 19:19
You may want to mention _os.exit directly after “the only way to defeat it is to crash the compiler”. Right now it’s mixed inbeteween examples where finally wins.
– Steven M. Vascellaro
Mar 13 '18 at 21:45
You may want to mention _os.exit directly after “the only way to defeat it is to crash the compiler”. Right now it’s mixed inbeteween examples where finally wins.
– Steven M. Vascellaro
Mar 13 '18 at 21:45
2
2
@StevenVascellaro I don't think that's necessary -
os._exit
is, for all practical purposes, the same as inducing a crash (unclean exit). The correct way to exit is sys.exit
.– wim
Mar 13 '18 at 22:58
@StevenVascellaro I don't think that's necessary -
os._exit
is, for all practical purposes, the same as inducing a crash (unclean exit). The correct way to exit is sys.exit
.– wim
Mar 13 '18 at 22:58
|
show 1 more comment
According to the Python documentation:
No matter what happened previously, the final-block is executed once the code block is complete and any raised exceptions handled. Even if there's an error in an exception handler or the else-block and a new exception is raised, the code in the final-block is still run.
It should also be noted that if there are multiple return statements, including one in the finally block, then the finally block return is the only one that will execute.
add a comment |
According to the Python documentation:
No matter what happened previously, the final-block is executed once the code block is complete and any raised exceptions handled. Even if there's an error in an exception handler or the else-block and a new exception is raised, the code in the final-block is still run.
It should also be noted that if there are multiple return statements, including one in the finally block, then the finally block return is the only one that will execute.
add a comment |
According to the Python documentation:
No matter what happened previously, the final-block is executed once the code block is complete and any raised exceptions handled. Even if there's an error in an exception handler or the else-block and a new exception is raised, the code in the final-block is still run.
It should also be noted that if there are multiple return statements, including one in the finally block, then the finally block return is the only one that will execute.
According to the Python documentation:
No matter what happened previously, the final-block is executed once the code block is complete and any raised exceptions handled. Even if there's an error in an exception handler or the else-block and a new exception is raised, the code in the final-block is still run.
It should also be noted that if there are multiple return statements, including one in the finally block, then the finally block return is the only one that will execute.
edited Mar 13 '18 at 19:25
Steven M. Vascellaro
5,69994291
5,69994291
answered Mar 13 '18 at 19:24
jaycejayce
18113
18113
add a comment |
add a comment |
Well, yes and no.
What is guaranteed is that Python will always try to execute the finally block. In the case where you return from the block or raise an uncaught exception, the finally block is executed just before actually returning or raising the exception.
(what you could have controlled yourself by simply running the code in your question)
The only case I can imagine where the finally block will not be executed is when the Python interpretor itself crashes for example inside C code or because of power outage.
ha ha .. or there is a infinite loop in try catch
– sapy
Mar 13 '18 at 17:46
2
Is it uncatched or uncaught?
– Stan Strum
Mar 13 '18 at 20:53
@StanStrum: Fixed. Sorry for the mistake, but English is not my first language...
– Serge Ballesta
Mar 14 '18 at 7:38
@SergeBallesta No biggie. At least here in rural UK plenty of people say "catched". Natives too.
– Wilson
Mar 14 '18 at 13:58
I think "Well, yes and no" is most correct. Finally: always wins where "always" means the interpreter is able to run and the code for the "finally:" is still available, and "wins" is defined as the interpreter will try to run the finally: block and it will succeed. That's the "Yes" and it is very conditional. "No" is all the ways the interpreter might stop before "finally:"- power failure, hardware failure, kill -9 aimed at the interpreter, errors in the interpreter or code it depends on, other ways to hang the interpreter. And ways to hang inside the "finally:".
– Bill IV
Mar 15 '18 at 0:25
add a comment |
Well, yes and no.
What is guaranteed is that Python will always try to execute the finally block. In the case where you return from the block or raise an uncaught exception, the finally block is executed just before actually returning or raising the exception.
(what you could have controlled yourself by simply running the code in your question)
The only case I can imagine where the finally block will not be executed is when the Python interpretor itself crashes for example inside C code or because of power outage.
ha ha .. or there is a infinite loop in try catch
– sapy
Mar 13 '18 at 17:46
2
Is it uncatched or uncaught?
– Stan Strum
Mar 13 '18 at 20:53
@StanStrum: Fixed. Sorry for the mistake, but English is not my first language...
– Serge Ballesta
Mar 14 '18 at 7:38
@SergeBallesta No biggie. At least here in rural UK plenty of people say "catched". Natives too.
– Wilson
Mar 14 '18 at 13:58
I think "Well, yes and no" is most correct. Finally: always wins where "always" means the interpreter is able to run and the code for the "finally:" is still available, and "wins" is defined as the interpreter will try to run the finally: block and it will succeed. That's the "Yes" and it is very conditional. "No" is all the ways the interpreter might stop before "finally:"- power failure, hardware failure, kill -9 aimed at the interpreter, errors in the interpreter or code it depends on, other ways to hang the interpreter. And ways to hang inside the "finally:".
– Bill IV
Mar 15 '18 at 0:25
add a comment |
Well, yes and no.
What is guaranteed is that Python will always try to execute the finally block. In the case where you return from the block or raise an uncaught exception, the finally block is executed just before actually returning or raising the exception.
(what you could have controlled yourself by simply running the code in your question)
The only case I can imagine where the finally block will not be executed is when the Python interpretor itself crashes for example inside C code or because of power outage.
Well, yes and no.
What is guaranteed is that Python will always try to execute the finally block. In the case where you return from the block or raise an uncaught exception, the finally block is executed just before actually returning or raising the exception.
(what you could have controlled yourself by simply running the code in your question)
The only case I can imagine where the finally block will not be executed is when the Python interpretor itself crashes for example inside C code or because of power outage.
edited Mar 14 '18 at 7:37
answered Mar 13 '18 at 17:38
Serge BallestaSerge Ballesta
79.7k957132
79.7k957132
ha ha .. or there is a infinite loop in try catch
– sapy
Mar 13 '18 at 17:46
2
Is it uncatched or uncaught?
– Stan Strum
Mar 13 '18 at 20:53
@StanStrum: Fixed. Sorry for the mistake, but English is not my first language...
– Serge Ballesta
Mar 14 '18 at 7:38
@SergeBallesta No biggie. At least here in rural UK plenty of people say "catched". Natives too.
– Wilson
Mar 14 '18 at 13:58
I think "Well, yes and no" is most correct. Finally: always wins where "always" means the interpreter is able to run and the code for the "finally:" is still available, and "wins" is defined as the interpreter will try to run the finally: block and it will succeed. That's the "Yes" and it is very conditional. "No" is all the ways the interpreter might stop before "finally:"- power failure, hardware failure, kill -9 aimed at the interpreter, errors in the interpreter or code it depends on, other ways to hang the interpreter. And ways to hang inside the "finally:".
– Bill IV
Mar 15 '18 at 0:25
add a comment |
ha ha .. or there is a infinite loop in try catch
– sapy
Mar 13 '18 at 17:46
2
Is it uncatched or uncaught?
– Stan Strum
Mar 13 '18 at 20:53
@StanStrum: Fixed. Sorry for the mistake, but English is not my first language...
– Serge Ballesta
Mar 14 '18 at 7:38
@SergeBallesta No biggie. At least here in rural UK plenty of people say "catched". Natives too.
– Wilson
Mar 14 '18 at 13:58
I think "Well, yes and no" is most correct. Finally: always wins where "always" means the interpreter is able to run and the code for the "finally:" is still available, and "wins" is defined as the interpreter will try to run the finally: block and it will succeed. That's the "Yes" and it is very conditional. "No" is all the ways the interpreter might stop before "finally:"- power failure, hardware failure, kill -9 aimed at the interpreter, errors in the interpreter or code it depends on, other ways to hang the interpreter. And ways to hang inside the "finally:".
– Bill IV
Mar 15 '18 at 0:25
ha ha .. or there is a infinite loop in try catch
– sapy
Mar 13 '18 at 17:46
ha ha .. or there is a infinite loop in try catch
– sapy
Mar 13 '18 at 17:46
2
2
Is it uncatched or uncaught?
– Stan Strum
Mar 13 '18 at 20:53
Is it uncatched or uncaught?
– Stan Strum
Mar 13 '18 at 20:53
@StanStrum: Fixed. Sorry for the mistake, but English is not my first language...
– Serge Ballesta
Mar 14 '18 at 7:38
@StanStrum: Fixed. Sorry for the mistake, but English is not my first language...
– Serge Ballesta
Mar 14 '18 at 7:38
@SergeBallesta No biggie. At least here in rural UK plenty of people say "catched". Natives too.
– Wilson
Mar 14 '18 at 13:58
@SergeBallesta No biggie. At least here in rural UK plenty of people say "catched". Natives too.
– Wilson
Mar 14 '18 at 13:58
I think "Well, yes and no" is most correct. Finally: always wins where "always" means the interpreter is able to run and the code for the "finally:" is still available, and "wins" is defined as the interpreter will try to run the finally: block and it will succeed. That's the "Yes" and it is very conditional. "No" is all the ways the interpreter might stop before "finally:"- power failure, hardware failure, kill -9 aimed at the interpreter, errors in the interpreter or code it depends on, other ways to hang the interpreter. And ways to hang inside the "finally:".
– Bill IV
Mar 15 '18 at 0:25
I think "Well, yes and no" is most correct. Finally: always wins where "always" means the interpreter is able to run and the code for the "finally:" is still available, and "wins" is defined as the interpreter will try to run the finally: block and it will succeed. That's the "Yes" and it is very conditional. "No" is all the ways the interpreter might stop before "finally:"- power failure, hardware failure, kill -9 aimed at the interpreter, errors in the interpreter or code it depends on, other ways to hang the interpreter. And ways to hang inside the "finally:".
– Bill IV
Mar 15 '18 at 0:25
add a comment |
To really understand how it works, just run these two examples:
try:
1
except:
print 'except'
finally:
print 'finally'
will output
finally
try:
1/0
except:
print 'except'
finally:
print 'finally'
will output
except
finally
add a comment |
To really understand how it works, just run these two examples:
try:
1
except:
print 'except'
finally:
print 'finally'
will output
finally
try:
1/0
except:
print 'except'
finally:
print 'finally'
will output
except
finally
add a comment |
To really understand how it works, just run these two examples:
try:
1
except:
print 'except'
finally:
print 'finally'
will output
finally
try:
1/0
except:
print 'except'
finally:
print 'finally'
will output
except
finally
To really understand how it works, just run these two examples:
try:
1
except:
print 'except'
finally:
print 'finally'
will output
finally
try:
1/0
except:
print 'except'
finally:
print 'finally'
will output
except
finally
answered Nov 24 '18 at 23:34
BasjBasj
6,34832107235
6,34832107235
add a comment |
add a comment |
protected by heemayl Mar 14 '18 at 18:15
Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).
Would you like to answer one of these unanswered questions instead?
14
The only case I can imagine
finally
fail to execute or "defeat its purpose" is during an infinite loop,sys.exit
or a forced interrupt. The documentation states thatfinally
is always executed, so I'd go with that.– Xay
Mar 13 '18 at 17:40
1
A bit of lateral thinking and sure not what you asked, but I'm pretty sure that if you open Task Manager and kill the process,
finally
will not run. Or the same if the computer crashes before :D– Alejandro
Mar 13 '18 at 19:18
120
finally
will not execute if the power cord is ripped from the wall.– immibis
Mar 13 '18 at 20:33
3
You might be interested in this answer to the same question about C#: stackoverflow.com/a/10260233/88656
– Eric Lippert
Mar 14 '18 at 14:40
1
Block it on an empty semaphore. Never signal it. Done.
– Martin James
Mar 14 '18 at 19:56