What is an Assertion
Assertions were invented as a debugging tool to check conditions that “should always be true if the code is correct.” For example, if we want to assert that a variable a
must be greater than 2, we can write:
assert a > 2
When the condition is not met, an AssertionError
exception is raised, equivalent to the following code:
if not assert_condition:
raise AssertionError
Since assertions are a debugging tool, Python’s implementation aligns with this philosophy. In Python, the execution of the assert
statement depends on the __debug__
variable. The assert
statement will only be executed if __debug__
is true.
if __debug__ and not assert_condition:
raise AssertionError
By default, when we run a Python file, __debug__
is set to True. It is only set to False when the -O
or -OO
parameter is used.
Create a new assert.py
file and write the following code:
print(__debug__)
assert 2 > 5
When running with python assert.py
, __debug__
will output True, and the statement assert 2 > 5
will raise an AssertionError
.
When running with python -O assert.py
, __debug__
will output False, and the statement assert 2 > 5
will not execute, so no exception will be raised.
Assertion or Exception
Let’s consider these questions: In what situations should assertions be used? What is the difference between exceptions and assertions?
To summarize the usage scenarios for assertions and their difference from exceptions in one sentence:
Use assertions to check preconditions, and exceptions to check postconditions.
Let’s define a read_file
function:
def read_file(file_path):
pass
The read_file
function requires certain conditions to be met at the start of execution: file_path
must be of type str
. This condition is a precondition, and if it is not met, the function should not be called. If such a situation arises, it indicates a bug in the code. In this case, we can use an assert
statement to infer the type of file_path
and remind the programmer to modify the code. Such inference is not needed in a production environment. Although we could use an if + raise
statement to achieve the same result as assert
, it would be much more cumbersome.
def read_file(file_path):
assert isinstance(file_path, str)
After the read_file
function is called and executed, it still needs to satisfy certain conditions, such as the file specified by file_path
must exist and the current user must have permission to read it. These conditions are called postconditions, and for checking postconditions, we need to use exceptions.
def read_file(file_path):
assert isinstance(file_path, str)
if not check_exist(file_path):
raise NotFoundError()
if not has_privilege(file_path):
raise PermissionError()
File non-existence and lack of permission are not code bugs; they are part of the code logic. The upper-level code may execute other logic after catching these exceptions, so we cannot allow this part of the code to be ignored in a production environment. Moreover, compared to assert
statements that can only raise AssertionError
, using exceptions allows for more detailed errors, enabling the upper-level code to execute different logic for different errors.