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

Question:

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.

Asked By: ElenaT

||

Answers:

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.

Answered By: Michael Hoffman

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 😉

Answered By: Raymond Hettinger

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.)

Answered By: Josh Imhoff

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)
Answered By: jathanism

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”).

Answered By: user159088

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

Answered By: wim

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
Answered By: SarthAk