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.

ElenaT
  • 2,600
  • 4
  • 24
  • 41
  • 3
    Looks like just pure laziness? http://www.gossamer-threads.com/lists/python/dev/484210 – Mike Christensen Nov 28 '11 at 21:10
  • @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 ... – ElenaT Nov 28 '11 at 21:15
  • 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. – Mike Christensen Nov 28 '11 at 21:17
  • @Mike Christensen: Ups... missed that. Indeed, for situations like the one described it would make sense. – ElenaT Nov 28 '11 at 21:23

7 Answers7

26

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

Raymond Hettinger
  • 216,523
  • 63
  • 388
  • 485
  • 4
    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. – calebds Nov 29 '11 at 02:12
  • 3
    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. – Peter Graham Nov 29 '11 at 02:44
  • 3
    I think people forget that code in a `finally` block IS ALWAYS EXECUTED. – jathanism Nov 29 '11 at 19:47
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

wim
  • 338,267
  • 99
  • 616
  • 750
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.

Michael Hoffman
  • 32,526
  • 7
  • 64
  • 86
  • Seems like a good explanation to me. Combination of `finally` and `continue` is definitely something that would be worth refactoring. – jsalonen Nov 28 '11 at 21:19
  • 2
    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. – Mike Christensen Nov 28 '11 at 21:24
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.)

Josh Imhoff
  • 6,746
  • 3
  • 13
  • 10
  • "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 reason – Artyer Feb 24 '22 at 17:41
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)
Community
  • 1
  • 1
jathanism
  • 33,067
  • 9
  • 68
  • 86
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").

  • 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.) – ashastral Jun 25 '12 at 00:57
-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
SarthAk
  • 1,628
  • 3
  • 19
  • 24