This is not a duplicate of the various why does a finally suppress my exception questions.
Instead, I find that finally
's local variables are unexpected, but only in the case of an exception. In that case, the exception disappears.
(This is on Python 3.8)
def test(divisor):
print(f"\n\ntest({divisor=})")
exc = None # always assigned!
foo = 1
print(f" ante.{exc=}")
try:
_ = 1 / divisor
print(f" post.{exc=}")
except (Exception,) as exc:
print(f" except.{exc=}")
else:
print(f" else.{exc=}")
finally:
print(f" finally:{locals()=}")
#at this point, it should be either None
#whatever was caught in the except clause
print(f" finally.{exc=}")
test(1)
test(0)
Output in the case of success - as expected:
test(divisor=1)
ante.exc=None
post.exc=None
else.exc=None
finally:locals()={'divisor': 1, 'exc': None, 'foo': 1, '_': 1.0}
finally.exc=None
On an exception - UnboundLocalError
It looks like the local namespace had exc
deleted and this causes an UnboundLocalError error.
I'd expect it to have the ZeroDivisionError. At most, if except
was defining a local scope for some reason, it could be still be None
. But it's just gone.
as if del locals()["exc"]
had taken place.
test(divisor=0)
ante.exc=None
except.exc=ZeroDivisionError('division by zero')
finally:locals()={'divisor': 0, 'foo': 1}
Traceback (most recent call last):
File "test_195_finally.py:27", in <module>
test(0)
File "test_195_finally.py:23", in test
print(f" finally.{exc=}")
UnboundLocalError: local variable 'exc' referenced before assignment
Binding exc
to another variable shows that other variable is alive and well.
except (Exception,) as exc:
exc2=exc
finally:locals()={'divisor': 0, 'foo': 1, 'exc2': ZeroDivisionError('division by zero')}