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 .