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, so assert
is fine.
assert
discourages the caller from handling the exception, since AssertionError
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:
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.)
assert x > 0
at the beginning of the function with dozens of repetitions of same outside the function. Worse, another time the function is called someone will forget to add the assert
- max 2012-04-04 21:17
assert
is placed. I suppose it was implied - max 2012-04-04 21:27
If the function you are writing/reusing is valid with positive or negative numbers, it is not the method that should contain the assert. The function calling the re-used function should have the assert because it is the function providing the invalid values to the function.
function x() {
var i;
// logic to set i. use assertion to test the logic.
assert(i > 0);
reusedFunc(i);
}
if reusedFunc(i) is not valid with negative numbers, it should throw an exception if passed a negative value.
assert
only to catch a bug in the code from the current scope or inner scope? I've never seen this clearly stated, but it sounds like a good approach. Let me think about it. BTW, I refer to Python, but it doesn't seem to matter in the example you gave - max 2012-04-04 21:26
assert
statements are for things that you use while developing and debugging the code, not to guarantee critical API constraints.
For your positive number example, test the value and raise ValueError
with a useful error message if using a negative value within your code would have bad consequences.
I tell people never to use assert statements. They are easy to write but yet they are so often inappropriate.
assert
statements also fall over when people write long ones and decide to use parentheses to make the statement and message span multiple lines... This generates a SyntaxWarning
in modern Python about the tuple that the author inadvertently created by using (condition, message) on a non-function statement but it hasn't always done so.
Another rule of thumb: If you ever see a unittest verifying that an AssertionError
was raised, the code should not be using an assert.
If you don't use assert
statements none of these things will ever bite you.
assert
for checks regarding values from the outside". If you get the area of something from some internal helper function, it may be worth toassert area >= 0
(in the calling code, or next to the complicated symbolic math that does the calculation) - NoName 2012-04-04 21:01