The best practice seems to be to use assert
for a condition that should never happen if the code is correct, and an exception for a condition that is a bit unusual but can happen (e.g., when memory runs out, or user input is invalid, or external connections are broken). I understand the rationale behind this practice as follows:
assert
will be disabled with -O interpreter flag. Conditions that may arise from external factors must not be allowed to be silently ignored, so assert there is inappropriate. OTOH, conditions that may only arise if my code is incorrect are hopefully eliminated through testing and debugging, soassert
is fine.assert
discourages the caller from handling the exception, sinceAssertionError
is usually interpreted as "don't catch me, this is a catastrophic failure". Furthermore, it is too generic to catch. This is perfect when a bug is found; the typical handling for that would be to stop the execution and debug the code. It is not good if it's a common condition due to external reasons.
Suppose I write some code where I ensure that a certain function argument is always positive. If I find it to be negative, clearly I made a mistake in the code. Hence, I am going to assert
that the argument is positive.
Later, someone finds this function useful in another application. They import it, and send all sorts of data to it. Now from the perspective of my function, receiving a negative value is actually quite likely; it is simply an invalid user input. Arguably, the assert
is no longer appropriate, and should be replaced with an exception.
Since almost any code could potentially be reused one day, often without my knowledge, this argument seems to say "never use assert
; only use exceptions". Obviously, this is not an accepted practice. What am I missing?
EDIT:
To be more specific, let's say the function cannot handle a negative argument at all. So once the argument is negative, the function will do one of the following:
- raise an exception
- fail an assert
- continue execution, likely producing incorrect output
I can see how it would be nice if negative arguments were caught by the caller. But if the calls to the function are interspersed in dozens of places around the code, it's arguably detrimental to the code clarity due to the numerous repetitions of the same check. (Not to mention, it could be forgotten by accident.)