An example of a method in Python that gracefully uses assert assertions

  • 2021-12-04 10:34:18
  • OfStack

Directory What Is assert Assertion Use scenarios for assertions and exceptions Several principles for using assertions suggest cases where assertions are not used: summary

What is an assert assertion

Assert statements are a convenient way to insert debugging assertions into a program

Assertion declaration is a convenient way to debug programs. Assertion can be seen as an debug tool, and the implementation of Python conforms to this design philosophy. In Python, the execution of assert statement depends on the built-in variable __debug__, whose default value is True. The assert statement is executed only when __debug__ is True.

For a 1-like declaration, assert expression is equivalent to


if __debug__:
    if not expression: raise AssertionError

assert can declare two expression at the same time, such as assert expression1, expression2 equivalent to


if __debug__:
    if not expression1: raise AssertionError(expression2)

If the script file is executed with the -O parameter, __debug__ is False

As an example, suppose we have a script testAssert. py that reads:


print(__debug__)
assert 1 > 2

When running with python assert. py, __debug__ outputs True, assert 1 > The 2 statement throws an AssertionError exception.

When running with python-O assert. py, __debug__ outputs False, assert 1 > The 2 statement will not report any exception because it is not executed.

Use scenarios for assertions and exceptions

Let's start with the conclusion:

Check prior condition usage assertion and check posterior condition usage exception

For example, under 1, we often encounter the scene of reading local files in development. We define an read_file method.


def read_file(path):
    assert isinstance(file_path, str)
    ...

The read_file function requires that 1 condition be satisfied at the beginning of execution: file_path must be str type. This condition is a priori condition. If it is not met, this function cannot be called. If the condition is not met, it proves that bug appears in the code. At this time, we can use assert statement to infer the type of file_path and remind programmers to modify the code. We can also use if... raise... statement to realize assert, but it is much more cumbersome. In many excellent Python projects, we can see the use of assert for prior judgment, which can be paid more attention to at ordinary times.

After the read_file function is called and executed, it still needs to meet 1 certain conditions. For example, the file specified by file_path needs to exist, and the current user has permission to read the file. These conditions are called posterior conditions. For the inspection of posterior conditions, we need to use exceptions to handle them.


def read_file(file_path):
    assert isinstance(file_path, str)
    if not check_exist(file_path):
        raise FileNotFoundError()
    if not has_privilege(file_path):
        raise PermissionError()

The file does not exist and has no permission. These two cases do not belong to the code bug, but are part of the code logic. The upper-level code may execute other logic after catching exceptions, so we cannot accept that this part of the code is ignored in the production environment, which is a posterior condition. Moreover, compared with assert statement, which can only throw AssertionError, exception can throw more detailed errors, which is convenient for upper-level code to execute different logic for different errors.

Several Principles of Using Assertions

Use assertions to catch illegal situations that should not occur. Don't confuse the difference between illegal and wrong situations, which are inevitable and must be dealt with.
Use assertions to validate the parameters of a function. When you write a function, you should repeatedly examine it and ask yourself, "What assumptions do I intend to make?" 1 Once the assumption is determined, it is necessary to use assertions to check the assumption. All textbooks encourage programmers to design error-proof programs, but remember that this programming style will conceal errors. When doing error-proofing programming, if something "impossible" does happen, use assertions to alert.

Assertions can also be used for code testing, as a unit test for a toy developer, as long as you accept that this test does nothing when using the-O flag. I sometimes use "assert Fasle" in my code to mark branches that haven't been implemented yet, and of course I hope they fail. If it is a little more detailed, perhaps triggering NotImplementedError is a better choice

Another place where assertions are used well is to check invariants in programs. An invariant is a condition that you can believe to be true unless a defect causes it to become false. If there is a bug, the sooner it is found, the better, so we need to test it, but we don't want to let these tests affect the code execution speed. Therefore, with assertion, it can take effect at development time and fail in product.

Assertion is also a good checkpoint comment. To replace the following note:


# When we execute here, we know that n>2 
 
# You can be sure to use the following assertions at runtime: 
 
assert n > 2

Cases where assertions are not recommended:

Do not use it to test user-supplied data, or where the check needs to be changed in all cases Do not use it to check where you think it may fail in normal use. Assertions are used for very special failure conditions. Your users will never see an AssertionError. If they do, it is a defect that must be fixed. In particular, don't use an assertion because it is only shorter than an explicit test plus a trigger exception. Assertion is not a shortcut for lazy code writers. Do not use assertions to check input parameters of public function libraries, because you can't control the caller, and you can't guarantee that it won't break the contract of the function. Don't use assertions for any errors you expect to fix. In other words, you have no reason to catch an AssertionError exception in the product code. Don't use assertions too much, they make the code obscure.

Summarize


Related articles: