Why is `continue` not allowed in a `finally` clause in Python?
Asked Answered
P

7

43

The following code raises a syntax error:

>>> for i in range(10):
...     print i
...     try:
...        pass
...     finally:
...        continue
...     print i
...
  File "<stdin>", line 6
SyntaxError: 'continue' not supported inside 'finally' clause

Why isn't a continue statement allowed inside a finally clause?

P.S. This other code on the other hand has no issues:

>>> for i in range(10):
...     print i
...     try:
...        pass
...     finally:
...        break
...
0

If it matters, I'm using Python 2.6.6.

Painty answered 28/11, 2011 at 21:5 Comment(4)
Looks like just pure laziness? gossamer-threads.com/lists/python/dev/484210Prehuman
@Mike Christensen: I also found that thread, but the docs say "continue may only occur syntactically nested in a for or while loop, but not nested in a function or class definition or finally clause within that loop". So was this laziness or it was something deliberate that later needed a change? ... like so many things in Python ...Painty
Did you read the whole thread? - There's some interesting info towards the bottom about what it would actually mean to continue in a finally block, and various issues that may come up. Worth the read.Prehuman
@Mike Christensen: Ups... missed that. Indeed, for situations like the one described it would make sense.Painty
N
25

The use of continue in a finally-clause is forbidden because its interpretation would have been problematic. What would you do if the finally-clause were being executed because of an exception?

for i in range(10):
    print i
    try:
       raise RuntimeError
    finally:
       continue        # if the loop continues, what would happen to the exception?
    print i

It is possible for us to make a decision about what this code should do, perhaps swallowing the exception; but good language design suggests otherwise. If the code confuses readers or if there is a clearer way to express the intended logic (perhaps with try: ... except Exception: pass; continue), then there is some advantage to leaving this as a SyntaxError.

Interestingly, you can put a return inside a finally-clause and it will swallow all exceptions including KeyboardInterrupt, SystemExit, and MemoryError. That probably isn't a good idea either ;-)

Nellienellir answered 28/11, 2011 at 21:30 Comment(3)
I agree. The usage of a finally clause is generally to tie up loose ends if an exception interrupted your procedure. To "finally continue" (also nonsensical in English) would run the risk of repeating the exception until the loop terminated, or even infinitely repeating it, if there were a problem affecting the loop condition itself.Bridoon
A continue in a finally block could be handled in the same way as a return or a raise. In this example the exception would be swallowed and the loop would continue.Atterbury
I think people forget that code in a finally block IS ALWAYS EXECUTED.Hawthorn
E
6

The Python Language Reference forbids the use of continue within a finally clause. I'm not entirely sure why. Perhaps because continue within the try clause ensures that the finally is executed, and deciding what continue should do within the finally clause is somewhat ambiguous.

Edit: @Mike Christensen's comment to the question points out a thread where this construction's ambiguity is discussed by Python core developers. Additionally, in more than nine years of Python use, I've never wanted to do this, so it's probably a relatively uncommon situation that developers don't feel like spending much time on.

Epispastic answered 28/11, 2011 at 21:17 Comment(2)
Seems like a good explanation to me. Combination of finally and continue is definitely something that would be worth refactoring.Blackpoll
Yea in these cases, it's sometimes better to just not allow developers to do something - otherwise you have to spec, address and fix any weirdness that arises from the decision to allow such things.Prehuman
D
6

A continue statement was illegal in the finally clause due to a problem with the implementation. In Python 3.8 this restriction was lifted.

The bug was issue32489 - Allow 'continue' in 'finally' clause.

The pull request for the fix: https://github.com/python/cpython/pull/5822

Diacaustic answered 20/4, 2018 at 5:27 Comment(0)
T
2

I think the reason for this is actually pretty simple. The continue statement after the finally keyword is executed every time. That is the nature of the finally statement. Whether or not your code throws an exception is irrelevant. Finally will be executed.

Therefore, your code...

for i in range(10):
   print i
   try:
       pass
   finally:
       continue
   print i # this (and anything else below the continue) won't ever be executed!

is equivalent to this code...

for i in range(10:
    print i
    try:
        pass
    finally:
        pass

which is cleaner and terser. Python does not allow continue in a finally block because all code after the continue will never be executed. (Sparse is better than dense.)

Thetisa answered 29/11, 2011 at 2:2 Comment(1)
"The continue statement after the finally keyword is executed every time": Not if continue isn't the only statement, like if it were if something: continue. And Python doesn't make it a SyntaxError if you have unreachable code after a continue normally, so this isn't really a valid reasonInjustice
H
2

I didn't see it mentioned in another response, but I think what you might want in this case is try..else:

for i in range(10):
    print i
    try:
       #pass <= I commented this out!
       do_something_that_might_fail(i)
    except SomeException:
       pass
    else:
       continue
    print i

The else block is only executed if there was no exception. So what this means is:

  1. We print i
  2. We try to do_something_that_might_fail(i)
  3. If it throws SomeException, fall through and print i again
  4. Otherwise, we continue (and i is never printed)
Hawthorn answered 29/11, 2011 at 19:55 Comment(0)
I
2

The possibility of getting an exception raised and then just swallowed because you're using a continue is a strong argument, but the exception is also swallowed when you use a break or return instead.

For example, this works and the exception is swallowed:

for i in range(10):
    print i
    try:
        raise Exception
    finally:
        break
    print i       # not gonna happen

This again works with no error (when in a function) and the exception is swallowed too:

for i in range(10):
    print i
    try:
        raise Exception
    finally:
        return
    print i       # not gonna happen

So why would break and return be allowed in a finally block, with or without possible raised errors, but continue not?

You might also consider the combination of the following factors in the issue:

  • finally is always executed;
  • continue "aborts" the current iteration.

This will mean that inside each loop, because of the finally always executing, you will always have a continue witch basically says "abort current iteration", "abort current iteration", "abort current iteration" ... witch doesn't really make any sense. But it doesn't make sense either to use break and return. The current iteration is also aborted with the only difference that you now end up with just one iteration.

So the question "Why is continue not allowed in a finally?" can also be asked as "Why is break and return allowed?".

Maybe because it made sense not to at that point? It was the developers decision and now its like it is? Sure, it might also be implementor's laziness but who knows, maybe they had something in mind and perhaps, in another version of Python, it would make more sense to have it another way?

The idea is that the examples here are just extreme. You don't just write code like that, do you? There is sure to be some logic in the finally block to say when to break/return/continue, whatever, and not just have it blunt like that. As such, IMHO continue inside a finally should be allowed because I would appreciate writing a clean code with using continue in finally if that's what I need, instead of resorting to a code workaround for this limitation (i.e. in Python's philosophy "We're all consenting adults here").

Indefensible answered 30/11, 2011 at 21:50 Comment(1)
I'm a bit late to this discussion, but a continue statement inside of a finally clause does not necessarily mean that every iteration will be aborted because you can wrap the continue statement inside of a conditional. (Which is still a SyntaxError.)Baldachin
T
-1

Now this feature is available with the release of 3.8

https://docs.python.org/3/whatsnew/3.8.html

Sample Code

def new_f():
    for i in range(0,24):
        try:
            print(1/0)
        except:
            print('In Exception')
        finally:
            print('In finally')
            continue
Tiossem answered 19/10, 2019 at 12:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.