design of python: why is assert a statement and not a function?
PythonLanguage DesignAssertPython Problem Overview
In Python, assert
is a statement, and not a function. Was this a deliberate decision? Are there any advantages to having assert
be a statement (and reserved word) instead of a function?
According to the docs, assert expression1, expression2
is expanded to
if __debug__:
if not expression1: raise AssertionError(expression2)
The docs also say that "The current code generator emits no code for an assert statement when optimization is requested at compile time." Without knowing the details, it seems like a special case was required to make this possible. But then, a special case could also be used to optimize away calls to an assert()
function.
If assert
were a function, you could write:
assert(some_long_condition,
"explanation")
But because assert
is a statement, the tuple always evaluates to True
, and
you get
SyntaxWarning: assertion is always true, perhaps remove parentheses?
The correct way to write it is
assert some_long_condition, \
"explanation"
which is arguably less pretty.
Python Solutions
Solution 1 - Python
> Are there any advantages to having assert be a statement (and reserved word) instead of a function?
- Cannot be reassigned to a user function, meaning it can be effectively disabled at compile time as @mgilson pointed out.
- The evaluation of the second, optional parameter is deferred until if/when the assertion fails. Awkward to do that with functions and function arguments (would need to pass a lambda.) Not deferring the evaluation of the second parameter would introduce additional overhead.
Solution 2 - Python
One of the wonderful things about assert
in python and in other languages (specifically C) is that you can remove them to optimize your code by just adding the correct #define
(optionally on the commandline with any compiler I've ever used) or optimization flags (-O
in python). If assert
became a function, this feature would be impossible to add to python as you don't know until runtime whether you have the builtin assert
function or user-defined function of the same name.
Also note that in python, function calls are reasonably expensive. Replacing inline with the code if __debug__: ...
is probably a lot more efficient than doing a function call which could be significant if you put an assert
statement in a performance critical routine.
Solution 3 - Python
In addition to the other answers (and sort of off-topic) a tip. To avoid the use of backslashes you can use implicit line joining inside parenthesis. ;-)
Instead of:
assert some_long_condition, \
"explanation"
You could write:
assert some_long_condition, (
"explanation")
Solution 4 - Python
I am no expert in Python, but I believe performance is one of the biggest reason.
if we have assert(expression, explanation) as function, if expression is expensive to evaluate, even we are in non-debug mode, Python needs to evaluate both expression to pass it to the assert function.
By expanding the assert, the expression and explanation statement is in fact not evaluated unless they are really needed (when debug evaluates to true). I believe it is critical if we want to make assert not affecting performance when not necessary (i.e. no performance hit in production system).