Python: fix SyntaxWarning: 'return' in a 'finally' block

The return of SyntaxWarning snake, finally!

Take this code:

import random


def d6() -> int:
    try:
        return random.randint(1, 6)
    except Exception:
        # Ignore issues in random number generation
        pass
    finally:
        # Fallback value chosen by a fair dice roll
        return 4


print("Your random number is:", d6())

Run it on Python 3.14+, and you’ll see:

$ python3.14 example.py
/.../example.py:12: SyntaxWarning: 'return' in a 'finally' block
  return 4
Your random number is: 4

Python reports a SyntaxWarning that indicates the return within the finally is dubious, likely to be an error, and may be removed from Python in the future.

And indeed, in this case, it is an error. d6() always returns its fallback value, 4, even though random number generation works. This is because a return in a finally block overrides the earlier return in the try block.

This confusion is why the SyntaxWarning was introduced, through PEP 765. The PEP introduced the warning for three statements within finally blocks:

  1. return, as above.

  2. break, as in:

    for i in range(5):
        try:
            ...
        finally:
            break
    

    …which warns like:

    $ python3.14 example.py
    /.../example.py:5: SyntaxWarning: 'break' in a 'finally' block
      break
    
  3. continue, as in:

    for i in range(5):
        try:
            ...
        finally:
            continue
    

    …which warns like:

    $ python3.14 example.py
    /.../example.py:5: SyntaxWarning: 'continue' in a 'finally' block
      continue
    

To fix the warning, rewrite your code to avoid using return, break, or continue within a finally block. This may mean removing the statement, or the finally block entirely, or restructuring your code to avoid the need for it. For example, in the d6() function above, we could move the return 4 within the except block:

import random


def d6() -> int:
    try:
        return random.randint(1, 6)
    except Exception:
        # Ignore issues in random number generation
        # Fallback value chosen by a fair dice roll
        return 4

Even better, we could remove the try/except entirely, since random.randint() is unlikely to raise an exception in normal use:

import random


def d6() -> int:
    return random.randint(1, 6)

Fin

We are finally free of this confusing pattern!

—Adam


😸😸😸 Check out my new book on using GitHub effectively, Boost Your GitHub DX! 😸😸😸


Subscribe via RSS, Twitter, Mastodon, or email:

One summary email a week, no spam, I pinky promise.

Related posts:

Tags: