The best time to use assertions is occasionally mentioned , It's usually because someone misuses it , So I think it's necessary to write an article about when to use assertions , Why should I use , When not to use .
For those who don't realize the best time to use assertions ,Python The assertion of is to detect a condition , If the condition is true , It does nothing ; Instead, it triggers a AssertionError. As shown in the following example ：
Many people use assertions as a quick and easy way to trigger exceptions when wrong parameter values are passed . But it's actually wrong , And it's a very dangerous mistake , There are two reasons . first ,AssertionError It's usually an error given when testing function parameters . You don't code like this ：
You should use TypeError To replace ,“ Assertion ” Resolved wrong exception type .
But what's more dangerous and tangled about assertions ： If you execute Python Used when -O or -OO Optimize identification , This can be compiled but never executed , In fact, there is no guarantee that the assertion will be executed . When assertions are used appropriately , This is very good , But when assertions are used inappropriately , in use -O When the identity executes, it will cause the code to be completely interrupted .
So when should we use assertions ? If there is no special purpose , Assertions should be used in the following situations ：
* defensive programming
* Detection of program logic at runtime
* Contractual inspection （ Such as preconditions , Post condition ）
* Constant in program
* Check documents
（ Assertions can also be used for code testing , Unit testing as a rough developer , As long as you can accept it -O This test doesn't do anything when it's marked . I also use it in code sometimes "assert
Fasle" To mark a branch that has not yet been implemented , Of course I hope they fail . If it's a little more detailed , Maybe triggered NotImplementedError It's a better choice ）
Because programmers show different confidence in code correctness , So opinions vary about when to use assertions . If you are sure the code is correct , So the assertion doesn't make any sense , Because they never fail , So you can safely remove them . If you are sure they will fail （ For example, detection of user input data ）, You can't assert it , So that compilation can pass , But you skipped your examination .
It's particularly interesting in between , That's when you believe the code is right , But not for sure . Maybe you've forgotten something strange about the corners （ Because we are all human beings ）, under these circumstances , Additional runtime checks will help you catch errors as early as possible , Instead of writing a lot of code .
（ That's why assertions are used at different times . Because we have different information about code correctness , A useful assertion for a person , It's a useless run-time test for another person .）
Another good place to use assertions is to check the invariants in the program . An invariant is something that you can believe is true , Unless a flaw makes it false . If there is a defect , The sooner you find out, the better , So we need to test it , But we don't want to affect the code execution speed because of these tests . So we use assertions , It works at development time and fails in the product .
An example of invariants might be . If your function expects an open database connection at the beginning , After the function returns, the database connection is still open , It's a function invariant ：
Assertions are also a good checkpoint comment . To replace the following note ：
# When we get here , We know n>2
You can ensure that the following assertions are used at run time ：
Assertions are also a defensive form of programming . You are not guarding against errors in the current code , To prevent errors due to future code changes . Ideally , Unit testing should be up to this point , But let's face it ： Even if unit tests exist , They're not perfect in general . Built in robots may not work , But no one has noticed it for weeks , Or people forget to run tests before committing code . Internal inspection will be another line of defense against error penetration , Especially for those who fail quietly , But the condition that causes code function error and returns error result is valid .
Suppose you have a series of if...elif Code block , You know in advance the expected value of the variable ：
Let's say this code is completely correct now . But will it always be right ? Requirements change , Code change . If the requirement becomes allowed target =
w, And related to run_w_code, What will happen then ? If we change the settings target Code of , But I forgot to change this code block , It will call in error run_z_code(), Errors will occur . The best way to do this is to write some defensive checks , So its execution , Even after the change , Either right , Or fail immediately .
Adding comments at the beginning of the code is a good place to start , But people don't like reading and updating these notes , These comments will soon become obsolete . But for assertions , We can document this code at the same time , If these assertions are violated , It will lead to a simple and direct failure .
The assertions here are used for both defensive programming and document checking . I think this is the best solution ：
This tempts developers to ignore code , Remove image value ==c This kind of unnecessary test , as well as RuntimeError Of “ Dead code ”. in addition , When "unexpected
error" This message will be very embarrassing when the error occurs , It does happen .
Contract design is another good place to assert . In contract design , We think that functions follow contracts with other callers , Like this ：
“ If you pass me a non empty string , I promise to return the initial converted to uppercase .”
If the contract is broken , Whether it's the function itself or the caller , It's all flawed . We say that this function needs to have preconditions （ Restrictions on expected parameters ） And post conditions （ Constraints on returned results ）. So this function might look like this ：
The purpose of contractual design is , In the right program , All preconditions and postconditions will be processed . This is a classic application of assertions , since （ This idea continues ） We release flawless programs and put them into the product , The program will be correct and we can safely remove the checks .
Here's where I recommend not using assertions ：
* Do not test user supplied data , Or where there is a need to change the check in all cases
* Don't use it to check what you think may fail in normal use . Assertions are used for very specific failure conditions . Your users will never see one AssertionError, If you see it , That's a defect that has to be fixed .
* In particular, don't use an assertion because it's smaller than a specific test plus a trigger exception . Assertions are not a shortcut for lazy code writers .
* Do not use assertions for checking input parameters of public function libraries , Because you can't control the caller , And there's no guarantee that it won't break the contract of the function .
* Do not use assertions for any errors that you expect to modify . In other words , You have no reason to capture one in the product code AssertionError abnormal .
* Don't use assertions too much , They obscure the code .