The question is how to use assertion expressions in some scenarios, which are often misused, so I decided to write an article explaining when to use assertions and when not.
For those who are not clear about it, the python assert is used to check a condition and, if it is true, does nothing. If it is false, it throws a Asserterror and contains an error message. For example:
py> x =
py> assert x > 0, "x is not zero or negative"
py> assert x%2 = 0, "X are not" a even number "
Traceback (most recent call last):
File" ", Line 1, in assertionerror:x be not a
even number
Many people use assert as a quick and easy way to throw an exception when the parameter is wrong. But this is wrong, very wrong, there are two reasons. First Asserterror is not an error that should be thrown when testing the parameters. You should not write code like this:
If not isinstance (x, int):
raise Assertionerror (' not a int ')
You should throw a typeerror error, and assert will throw the wrong exception.
But, more dangerously, there is a nagging obsession: it can be compiled and never executed, and if you run Python with the –o or –oo option, the result does not guarantee that the assert expression will run to. This is the future when the appropriate assert is used, but when assert is improperly used, it makes the code error when executing with-O.
When should you use assert? There are no specific rules, assertions should be used to:
- Defensive type of programming
- Run-time Check program logic
- Check Convention
- Program Constants
- Check Document
(It is also acceptable to use assertions when testing your code, and is a convenient unit test method that you accept that will not do anything when run with the-o flag.) I sometimes use assert false in my code to mark a branch of code that has not been written out, and I want the code to fail. Although throwing notimplementederror may be better. )
There is a lot of opinion about assertions because it ensures the correctness of the code. If you are sure that the code is correct, then there is no need to assert it, because they never fail to run, and you can simply remove those assertions. If you are certain that the inspection will fail, then if you do not assert the code will compile and ignore your check.
In both cases it would be interesting when you are more certain of the code but not absolutely sure. Maybe you'll miss out on some really weird situations. In this case, additional run-time checks can help you ensure that any errors are captured as early as possible.
Another good way to use assertions is to check the invariants of the program. A invariants is something you need to rely on to be true, unless a bug causes it to be false. If there is a bug, it's best to find it early, so let's do a test for it, but don't want to slow down the speed of the code. So use assertions because it can be opened at development time and closed at the product stage.
An example of a non variable might be that if your function wants to have a database connection at the beginning of it and promises to remain connected when it returns, this is the invariant of the function:
def some_function (ARG):
assert not db.closed () ...
# code goes here asserts not
db.closed ()
The assertion itself is a good comment, rather than writing a comment directly:
# When we reach this, we know that n > 2
You can make sure of it by adding assertions:
Assert n > 2
Assertions are also a defensive type of programming. You are not going to let your code defend against the current error, but to prevent errors that are raised after the code has been modified. Ideally, unit tests can do this, but the reality is that they are usually not done. People may forget to run the test code before submitting the code. An internal check is another line of defense that blocks the error, especially if the error is not obvious, causing the code to go wrong and return the wrong result.
Join you have some IF...ELIF statements block you know before that some need some value:
# target is expected to being one of X, Y, or Z, and nothing else.
If target = = x:
run_x_code ()
elif target = = y:
run_y_code ()
Else:
Run_z_code ()
Suppose the code is now completely correct. But will it always be right? Dependent modifications, code modifications. What happens if the dependency is modified to target = W, is it related to the Run_w_code function? If we change the code, but do not modify the code here, it may cause the wrong call to the Run_z_code function and raise an error. It would be nice to write code in a defensive way, either to make the code run correctly or to execute the error immediately, even if you modify it in the future.
Comments at the beginning of the code are a good step, but people are often too lazy to read or update comments. Once this happens, the annotation becomes useless. But with assertions, I can write documents about the assumptions of the blocks of code and trigger a clean error when they violate.
Assert target in (x, Y, z)
if target = = x:
run_x_code ()
elif target = = y:
run_y_code ()
else:
asse RT target = = Z
run_z_code ()
In this way, assertions are a defensive type of programming and a document. I think of a better plan:
If target = = x:
run_x_code ()
elif target = = y:
run_y_code ()
elif target = = Z:
run_z_code ()
Else:
# This can never happen. But just in case it does
... Raise RuntimeError ("An unexpected error occurred")
Design by convention is another good use of assertions. We imagine a convention between a function and the caller, such as the following:
"If you pass me a non-empty string, I guarantee the first letter of the string and capitalize it." ”
If the contract is corrupted by a function or call, the code will go wrong. We say that the function has some preconditions and a post condition, so the function writes:
def first_upper (astring):
assert Isinstance (astring, str) and Len (astring) > 0 Result
= Astring[0].upper () C3/>assert isinstance (result, str) and Len (result) = = 1
assert result = = Result.upper () return result
According to the agreed design goal is to correct programming, preconditions and post conditions need to be maintained. This is a typical scenario for assertions, because once we have released the code into the product, the program will be correct, and we can safely remove the check.
Here are the scenarios I suggest not to use assertions:
- Do not use it to test user-supplied data
- Don't use assertions to check where you feel you're going to make a mistake in your program's routine use. Assertions are used to check for very rare problems. Your users should not see any assertion errors if they see that it is a bug and fix it.
- In some cases, no assertion is because it is shorter than the precise inspection, it should not be lazy code farmers lazy way.
- Do not use it to check the input parameters of the public library, because it does not control the caller, so it is not guaranteed that the caller will break the agreement between the two parties.
- Do not use assertions for errors that you feel can be recovered. In other words, the assertion error is not captured in the product code.
- Don't use too many assertions to make your code obscure.