[Python-ideas] Repurpose `assert' into a general-purpose check
Steven D'Aprano
steve at pearwood.info
Tue Jan 16 05:23:27 EST 2018
On Tue, Jan 16, 2018 at 01:38:25AM -0800, smarie wrote:
> Typically ‘assert isfinite(x)‘ is today a good example of what is wrong:
>
> 1. it can be disabled globally by end-users even if the lib developer
> does not want it,
That's not a bug, or even a problem ("wrong"), it is the very purpose of
assert. Assertions are intended to allow the end user to disable the checks.
If you, the developer, don't want a check to be disabled, then you
shouldn't call it an assertion and use assert.
I sometimes wish that Python included a richer set of assertions rather
than just a single `assert` keyword. Something like Eiffel's concept of
pre-conditions, post-conditions and invariants, where each can be
enabled or disabled independently. But even with Python's sparse
assertion API, the reason for assert is for debugging checks which can
optionally be disabled.
Checks which should never be disabled don't belong as assertions.
> 2. if x is None the exception is different from the exception you get if
> x is not finite
This is a little untidy, but I don't see why this should be considered
"wrong". That's just the way Python operates: however you write a check,
it is going to rely on the check succeeding, and if it raises an
exception, you will see that exception.
That's a good thing, not "wrong" -- if my assertion isfinite(x) fails
because x is None, I'd much rather see a TypeError than
AssertionError: x is not finite
> 3. you can not customize the exception type for easy error codes
> internationalization, you can only customize the message.
assert is not intended to be used to present user-friendly error
messages to the end-user. The end-user should never see an
AssertionError, and if they do, that's a bug, not a recoverable error or
an avoidable environmental/input error.
I have come to the conclusion that a good way to think about assertions
is that they are often "checked comments". Comments like:
# when we get here, x is a finite number
quickly get out of sync with code. To quote Michael Foord:
"At Resolver we've found it useful to short-circuit any doubt
and just refer to comments in code as 'lies'. "
-- Michael Foord paraphrases Christian Muirhead on python-dev,
2009-03-22
Instead, turn it into an assertion, if you can:
assert isfinite(x)
which is both inline developer documentation ("x is a finite number")
and a debugging aid (it will fail during development is x is not a
finite number). And, if the cost of those assertions becomes excessive,
the end-user can disable them.
> My proposal would be to rather define another statement for example
>
> 'validate <expression> <exception, exception_type or
> exception_message>'
The problem with a statement called "validate" is that it will break a
huge number of programs that already include functions and methods using
that name.
But apart from the use of a keyword, we already have a way to do almost
exactly what you want:
if not expression: raise ValidationError(message)
after defining some appropriate ValidationError class. And it is only a
few key presses longer than the proposed:
validate expression, ValidationError, message
--
Steve
More information about the Python-ideas
mailing list