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 aAssertionError. 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 it.TypeError To replace,“ Assertion” Resolved wrong exception type.


But what's more dangerous and tangled about assertions: If you executePython When used-O or-OO Optimized logo, 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, Postcondition)
* Constant in program
* Inspection document
( 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 triggerNotImplementedError 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 known>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 ofif...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? Demand change, Code change. If the requirement becomes allowedtarget =
w, And related torun_w_code, What will happen then? If we change the settingstarget Code, But I forgot to change this code block, It will call in errorrun_z_code(), Errors will occur. The best way to do this is to write some defensive checks, So its execution, Even after the change, Or 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 imagevalue ==c This kind of unnecessary test, as well asRuntimeError 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 changes are needed 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 oneAssertionError, 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 codeAssertionError abnormal.

* Don't use assertions too much, They obscure the code.