2023-06-27
Belatedly remembering to use the two expression form of Python's assert
Today I confessed on the Fediverse that I had somehow
mentally overwritten what I once knew about Python's assert
with a C-like version that I wrote as
'assert(expression)
' (which I apparently started doing more
than a decade ago). What caused me to notice
this was that I was revising some Python code to cope with a new
situation, and I decided I wanted to fail in some way if an impossible
thing turned out to not be as impossible as I thought. This wasn't
an error that should be returned normally, and it wasn't really
something I wanted to raise as an assertion, so adding an assert
was the easy way.
So at first I wrote 'assert(2 <= n <= 23)
', and then in my way
deliberately forced the assert to fail to test things. This caused
me to change the variable name to make the assert slightly more
informational, as 'assert(2 <= disknum <= 23)
'. This gave a better
clue about what the assert was about, but it didn't say what was
wrong. Thinking about how to fix that caused a dim flickering light
to appear over my head and sent me off to read the specification
of assert
,
which told me about the two expression version and also reminded
me that assert
is a statement, not a C-like function call.
(My new use of assert
in my code hopefully includes enough
information about the surrounding context that I can see what
went wrong, if something does. It won't give me everything but
these are quick, low-effort checks that I don't expect to ever
trigger.)
Now that I've re-discovered this full form of assert
, my goal is
to use it more often for "this is never expected to happen" safety
checks in my code. Putting in a single line of an assert
can
convert an otherwise mysterious failure (like the famous 'NoneType
object has no attribute ...' error) into a more explicit one, and
prevent my code going off the rails in cases where it might not
fail immediately.
(I know, CPython will strip out these assert
statements if we
ever run with optimization enabled. We're unlikely to ever do that
for these Python programs.)
As a side note, in general Python's syntax allows for both putting
unnecessary ()'s around expressions and then not having a space between
a statement and an expression. This allows what would normally be
'assert expr
' to be transformed into 'assert(expr)
', so that it
looked like a function call to me. Fortunately there are only a few
simple statements that can even be potentially confused this way, and
I suspect I'm not likely to imagine 'raise
' or 'yield
' could be
function calls (or 'return
').
(You can write some complex statements this way, such as 'if(expr):
',
but then the ':' makes it clear that you have a statement, not a
function call.)