Cara menggunakan assert if python

Python’s

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement allows you to write sanity checks in your code. These checks are known as assertions, and you can use them to test if certain assumptions remain true while you’re developing your code. If any of your assertions turn false, then you have a bug in your code.

Show

Assertions are a convenient tool for documenting, debugging, and testing code during development. Once you’ve debugged and tested your code with the help of assertions, then you can turn them off to optimize the code for production. Assertions will help you make your code more efficient, robust, and reliable.

In this tutorial, you’ll learn:

  • What assertions are and when to use them
  • How Python’s
    number = 42
    
    assert (
        number > 0 and isinstance(number, int),
        f"number greater than 0 expected, got: {number}"
    )
    
    0 statement works
  • How
    number = 42
    
    assert (
        number > 0 and isinstance(number, int),
        f"number greater than 0 expected, got: {number}"
    )
    
    0 can help you document, debug, and test your code
  • How assertions can be disabled to improve performance in production
  • What common pitfalls you might face when using
    number = 42
    
    assert (
        number > 0 and isinstance(number, int),
        f"number greater than 0 expected, got: {number}"
    )
    
    0 statements

To get the most out of this tutorial, you should have previous knowledge of expressions and operators, functions, conditional statements, and exceptions. Having a basic understanding of documenting, debugging, and testing Python code is also a plus.

Free Download: Get a sample chapter from Python Tricks: The Book that shows you Python’s best practices with simple examples you can apply instantly to write more beautiful + Pythonic code.

Getting to Know Assertions in Python

Python implements a feature called assertions that’s pretty useful during the development of your applications and projects. You’ll find this feature in several other languages too, such as C and Java, and it comes in handy for documenting, debugging, and testing your code.

If you’re looking for a tool to strengthen your debugging and testing process, then assertions are for you. In this section, you’ll learn the basics of assertions, including what they are, what they’re good for, and when you shouldn’t use them in your code.

Remove ads

What Are Assertions?

In Python, assertions are that you can use to set sanity checks during the development process. Assertions allow you to test the correctness of your code by checking if some specific conditions remain true, which can come in handy while you’re debugging code.

The assertion condition should always be true unless you have a bug in your program. If the condition turns out to be false, then the assertion raises an exception and terminates the execution of your program.

With assertions, you can set checks to make sure that within your code stay invariant. By doing so, you can check assumptions like preconditions and postconditions. For example, you can test conditions along the lines of This argument is not

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
4 or This return value is a string. These kinds of checks can help you catch errors as soon as possible when you’re developing a program.

What Are Assertions Good For?

Assertions are mainly for debugging. They’ll help you ensure that you don’t introduce new bugs while adding features and fixing other bugs in your code. However, they can have other interesting use cases within your development process. These use cases include documenting and testing your code.

The primary role of assertions is to trigger the alarms when a bug appears in a program. In this context, assertions mean Make sure that this condition remains true. Otherwise, throw an error.

In practice, you can use assertions to check preconditions and postconditions in your programs at development time. For example, programmers often place assertions at the beginning of functions to check if the input is valid (preconditions). Programmers also place assertions before functions’ return values to check if the output is valid (postconditions).

Assertions make it clear that you want to check if a given condition is and remains true. In Python, they can also include an optional message to unambiguously describe the error or problem at hand. That’s why they’re also an efficient tool for documenting code. In this context, their main advantage is their ability to take concrete action instead of being passive, as comments and are.

Finally, assertions are also ideal for writing test cases in your code. You can write concise and to-the-point test cases because assertions provide a quick way to check if a given condition is met or not, which defines if the test passes or not.

You’ll learn more about these common use cases of assertions later in this tutorial. Now you’ll learn the basics of when you shouldn’t use assertions.

When Not to Use Assertions?

In general, you shouldn’t use assertions for data processing or data validation, because you can disable assertions in your production code, which ends up removing all your assertion-based processing and validation code. Using assertions for data processing and validation is a common pitfall, as you’ll learn in later in this tutorial.

Additionally, assertions aren’t an error-handling tool. The ultimate purpose of assertions isn’t to handle errors in production but to notify you during development so that you can fix them. In this regard, you shouldn’t write code that catches assertion errors using a regular statement.

Understanding Python’s number = 42 assert ( number > 0 and isinstance(number, int), f"number greater than 0 expected, got: {number}" ) 0 Statements

Now you know what assertions are, what they’re good for, and when you shouldn’t use them in your code. It’s time to learn the basics of writing your own assertions. First, note that Python implements assertions as a statement with the

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 keyword rather than as a function. This behavior can be a common source of confusion and issues, as you’ll learn later in this tutorial.

In this section, you’ll learn the basics of using the statement to introduce assertions in your code. You’ll study the syntax of the

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement. Most importantly, you’ll understand how this statement works in Python. Finally, you’ll also learn the basics of the exception.

The Syntax of the number = 42 assert ( number > 0 and isinstance(number, int), f"number greater than 0 expected, got: {number}" ) 0 Statement

An

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement consists of the
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 keyword, the expression or condition to test, and an optional message. The condition is supposed to always be true. If the assertion condition is true, then nothing happens, and your program continues its normal execution. On the other hand, if the condition becomes false, then
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 halts the program by raising an
number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
2.

In Python,

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 is a with the following syntax:

assert expression[, assertion_message]

Here,

number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
9 can be any valid Python expression or object, which is then tested for . If
number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
9 is false, then the statement throws an
number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
2. The
>>> number = 42
>>> assert(number > 0)

>>> number = -42
>>> assert(number > 0)
Traceback (most recent call last):
    ...
AssertionError
2 parameter is optional but encouraged. It can hold a string describing the issue that the statement is supposed to catch.

Here’s how this statement works in practice:

>>>

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError

With a truthy expression, the assertion succeeds, and nothing happens. In that case, your program continues its normal execution. In contrast, a falsy expression makes the assertion fail, raising an

number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
2 and breaking the program’s execution.

To make your

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statements clear to other developers, you should add a descriptive assertion message:

>>>

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42

The message in this assertion clearly states which condition should be true and what is making that condition fail. Note that the

>>> number = 42
>>> assert(number > 0)

>>> number = -42
>>> assert(number > 0)
Traceback (most recent call last):
    ...
AssertionError
2 argument to
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 is optional. However, it can help you better understand the condition under test and figure out the problem that you’re facing.

So, whenever you use

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0, it’s a good idea to use a descriptive assertion message for the traceback of the
number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
2 exception.

An important point regarding the

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 syntax is that this statement doesn’t require a pair of parentheses to group the expression and the optional message. In Python,
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 is a statement instead of a function. Using a pair of parentheses can lead to unexpected behaviors.

For example, an assertion like the following will raise a :

>>>

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?

This warning has to do with non-empty tuples always being truthy in Python. In this example, the parentheses turn the assertion expression and message into a two-item tuple, which always evaluates to true.

Fortunately, recent versions of Python throw a

>>> # Comparison assertions
>>> assert 3 > 2
>>> assert 3 == 2
Traceback (most recent call last):
    ...
AssertionError

>>> assert 3 > 2 and 5 < 10
>>> assert 3 == 2 or 5 > 10
Traceback (most recent call last):
    ...
AssertionError
1 to alert you of this misleading syntax. However, in older versions of the language, an
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement like the one above will always succeed.

This issue often appears when you’re using long expressions or messages that take more than a single line. In these cases, the parentheses are the natural way to format the code, and you may end up with something like the following:

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)

Using a pair of parentheses to split a long line into multiple lines is a common formatting practice in Python code. However, in the context of an

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement, the parentheses turn the assertion expression and message into a two-item tuple.

In practice, if you want to split a long assertion into several lines, then you can use the backslash character (

>>> # Comparison assertions
>>> assert 3 > 2
>>> assert 3 == 2
Traceback (most recent call last):
    ...
AssertionError

>>> assert 3 > 2 and 5 < 10
>>> assert 3 == 2 or 5 > 10
Traceback (most recent call last):
    ...
AssertionError
5) for :

number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"

The backslash at the end of first line of this assertion joins the assertion’s two into a single . This way, you can have appropriate without the risk of a warning or a logical error in your code.

Note: PEP 679 was created on January 7, 2022, and is proposing to allow parentheses around the assertion expression and message. If the PEP gets approved and implemented, then the issue of accidental tuples won’t affect Python code in the future.

There’s an edge case of this parentheses-related issue. If you provide only the assertion expression in parentheses, then

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 will work just fine:

>>>

>>> number = 42
>>> assert(number > 0)

>>> number = -42
>>> assert(number > 0)
Traceback (most recent call last):
    ...
AssertionError

Why is this happening? To create a single-item tuple, you need to place a comma after the item itself. In the code above, the parentheses by themselves don’t create a tuple. That’s why the interpreter ignores the parentheses, and

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 works as expected.

Even though the parentheses seem to work in the scenario described in the above example, it’s not a recommended practice. You can end up shooting yourself in the foot.

Remove ads

The number = 42 assert number > 0 and isinstance(number, int), \ f"number greater than 0 expected, got: {number}" 2 Exception

If the condition of an

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement evaluates to false, then
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 raises an . If you provide the optional assertion message, then this message is internally used as an argument to the
number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
2 class. Either way, the raised exception breaks your program’s execution.

Most of the time, you won’t raise

number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
2 exceptions explicitly in your code. The
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement takes care of raising this exception when the assertion condition fails. Additionally, you shouldn’t attempt to handle errors by writing code that catches the
number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
2 exception, as you’ll learn later in this tutorial.

Finally,

number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
2 is a built-in exception that inherits from the class and is considered a concrete exception that should be raised instead of subclassed.

That’s it! Now you know the basics of the

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement. You’ve learned the statement’s syntax, how
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 works in practice, and also what the main characteristics of the
number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
2 exception are. It’s time to move forward and explore some effective and common ways to write assertions in Python.

Exploring Common Assertion Formats

When it comes to writing the

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement, you’ll find several assertion formats that are common in Python code. Being aware of these formats will allow you to write better assertions.

The following examples showcase a few of these common assertion formats, starting with assertions that compare objects:

>>>

>>> # Comparison assertions
>>> assert 3 > 2
>>> assert 3 == 2
Traceback (most recent call last):
    ...
AssertionError

>>> assert 3 > 2 and 5 < 10
>>> assert 3 == 2 or 5 > 10
Traceback (most recent call last):
    ...
AssertionError

Comparison assertions are intended to test conditions that compare two or more objects using . These assertions can also include compound expressions based on Boolean operators.

Another common assertion format is related to tests:

>>>

>>> # Membership assertions
>>> numbers = [1, 2, 3, 4, 5]
>>> assert 4 in numbers
>>> assert 10 in numbers
Traceback (most recent call last):
    ...
AssertionError

Membership assertions allow you to check if a given item is present in a specific collection, such as a list, tuple, set, dictionary, or the like. These assertions use the membership operators,

>>> # Identity assertions
>>> x = 1
>>> y = x
>>> null = None

>>> assert x is y
>>> assert x is not y
Traceback (most recent call last):
    ...
AssertionError

>>> assert null is None
>>> assert null is not None
Traceback (most recent call last):
    ...
AssertionError
2 and , to perform the required check.

The assertion format in the example below is related to an object’s identity:

>>>

>>> # Identity assertions
>>> x = 1
>>> y = x
>>> null = None

>>> assert x is y
>>> assert x is not y
Traceback (most recent call last):
    ...
AssertionError

>>> assert null is None
>>> assert null is not None
Traceback (most recent call last):
    ...
AssertionError

Identity assertions provide a way to test for an object’s identity. In this case, the assertion expression uses the identity operators, and .

Finally, you’ll learn how to check the data type of your objects in the context of an assertion:

>>>

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
0

Type check assertions commonly involve using the built-in function to make sure that a given object is an instance of a certain class or classes.

Even though these are some of the most common assertion formats that you’ll find in Python code, there are many other possibilities. For example, you can use the built-in

>>> # Identity assertions
>>> x = 1
>>> y = x
>>> null = None

>>> assert x is y
>>> assert x is not y
Traceback (most recent call last):
    ...
AssertionError

>>> assert null is None
>>> assert null is not None
Traceback (most recent call last):
    ...
AssertionError
7 and
>>> # Identity assertions
>>> x = 1
>>> y = x
>>> null = None

>>> assert x is y
>>> assert x is not y
Traceback (most recent call last):
    ...
AssertionError

>>> assert null is None
>>> assert null is not None
Traceback (most recent call last):
    ...
AssertionError
8 functions to write assertions that check for the truth value of items in an iterable:

>>>

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
1

The

>>> # Identity assertions
>>> x = 1
>>> y = x
>>> null = None

>>> assert x is y
>>> assert x is not y
Traceback (most recent call last):
    ...
AssertionError

>>> assert null is None
>>> assert null is not None
Traceback (most recent call last):
    ...
AssertionError
7 assertions check if all the items in an input iterable are truthy, while the
>>> # Identity assertions
>>> x = 1
>>> y = x
>>> null = None

>>> assert x is y
>>> assert x is not y
Traceback (most recent call last):
    ...
AssertionError

>>> assert null is None
>>> assert null is not None
Traceback (most recent call last):
    ...
AssertionError
8 examples check if any item in the input iterable is truthy.

Your imagination is the only limit for writing useful assertions. You can write assertions using predicate or Boolean-valued functions, regular Python objects, comparison expressions, Boolean expressions, or general Python expressions. Your assertion will depend on what specific condition you need to check at a given moment.

Now you know some of the most common assertion formats that you can use in your code. It’s time to learn about specific use cases of assertions. In the following section, you’ll learn how to use assertions to document, debug, and test your code.

Remove ads

Documenting Your Code With Assertions

The

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement is an effective way to document code. For example, if you want to state that a specific
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
02 should always be true in your code, then
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
03 can be better and more effective than a comment or a docstring, as you’ll learn in a moment.

To understand why assertions can be a handy documenting tool, say that you have a function that takes a server name and a tuple of port numbers. The function will iterate over the port numbers trying to connect to the target server. For your function to work correctly, the tuple of ports shouldn’t be empty:

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
2

If someone accidentally calls

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
04 with an empty tuple, then the
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
05 loop will never run, and the function will return
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
4 even if the server is available. To alert programmers to this buggy call, you can use a comment, like you did in the example above. However, using an
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement can be more effective:

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
3

The advantage of an

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement over a comment is that when the condition isn’t true,
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 immediately raises an
number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
2. After that, your code stops running, so it avoids abnormal behaviors and points you directly to the specific problem.

So, using assertions in situations like the one described above is an effective and powerful way to document your intentions and avoid hard-to-find bugs due to accidental errors or malicious actors.

Debugging Your Code With Assertions

At its core, the

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement is a debugging aid for testing conditions that should remain true during your code’s normal execution. For assertions to work as a debugging tool, you should write them so that a failure indicates a bug in your code.

In this section, you’ll learn how to use the

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement to assist you while debugging your code at development time.

An Example of Debugging With Assertions

You’ll typically use assertions to debug your code during development. The idea is to make sure that specific conditions are and remain true. If an asserted condition becomes false, then you immediately know that you have a bug.

As an example, say that you have the following

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
13 class:

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
4

The class’s initializer, , takes

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
15 as an argument and makes sure that the input value is a positive number. This check prevents circles with a negative radius.

The

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
16 method computes the circle’s area. However, before doing that, the method uses an
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement to guarantee that
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
18 remains a positive number. Why would you add this check? Well, suppose that you’re working on a team, and one of your coworkers needs to add the following method to
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
13:

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
5

This method takes a correction coefficient and applies it to the current value of

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
18. However, the method doesn’t validate the coefficient, introducing a subtle bug. Can you spot it? Say that the user provides a negative correction coefficient by accident:

>>>

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
6

The first call to

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
16 works correctly because the initial radius is positive. But the second call to
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
16 breaks your code with an
number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
2. Why? This happens because the call to
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
24 turns the radius into a negative number, which uncovers a bug: the function doesn’t properly check for valid input.

In this example, your

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement works as a watchdog for situations in which the radius could take invalid values. The
number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
2 immediately points you to the specific problem:
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
18 has unexpectedly changed to a negative number. You have to figure out how this unexpected change happened and then fix your code before it goes into production.

Remove ads

A Few Considerations on Debugging With Assertions

Developers often use

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statements to state preconditions, just like you did in the above example, where
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
16 checks for a valid
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
18 right before doing any computation. Developers also use assertions to state postconditions. For example, you can check if a function’s return value is valid, right before returning the value to the caller.

In general, the conditions that you check with an

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement should be true, unless you or another developer in your team introduces a bug in the code. In other words, these conditions should never be false. Their purpose is to quickly flag if someone introduces a bug. In this regard, assertions are early alerts in your code. These alerts are meant to be useful during development.

If one of these conditions fails, then the program will crash with an

number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
2, telling you exactly which condition isn’t succeeding. This behavior will help you track down and fix bugs more quickly.

To properly use assertions as a debugging tool, you shouldn’t use

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
6 …
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
7 blocks that catch and handle
number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
2 exceptions. If an assertion fails, then your program should crash because a condition that was supposed to be true became false. You shouldn’t change this intended behavior by catching the exception with a
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
6 …
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
7 block.

A proper use of assertions is to inform developers about unrecoverable errors in a program. Assertions shouldn’t signal an expected error, like a

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
38, where a user can take a corrective action and try again.

The goal of assertion should be to uncover programmers’ errors rather than users’ errors. Assertions are useful during the development process, not during production. By the time you release your code, it should be (mostly) free of bugs and shouldn’t require the assertions to work correctly.

Finally, once your code is ready for production, you don’t have to explicitly remove assertions. You can just disable them, as you’ll learn in the following section.

Disabling Assertions in Production for Performance

Now say that you’ve come to the end of your development cycle. Your code has been extensively reviewed and tested. All your assertions pass, and your code is ready for a new release. At this point, you can optimize the code for production by disabling the assertions that you added during development. Why should you optimize your code this way?

Assertions are great during development, but in production, they can affect the code’s performance. For example, a codebase with many assertions running all the time can be slower than the same code without assertions. Assertions take time to run, and they consume memory, so it’s advisable to disable them in production.

Now, how can you actually disable your assertions? Well, you have two options:

  1. Run Python with the
    >>> number = 42
    >>> assert number > 0
    
    >>> number = -42
    >>> assert number > 0
    Traceback (most recent call last):
        ...
    AssertionError
    
    39 or
    >>> number = 42
    >>> assert number > 0
    
    >>> number = -42
    >>> assert number > 0
    Traceback (most recent call last):
        ...
    AssertionError
    
    40 options.
  2. Set the
    >>> number = 42
    >>> assert number > 0
    
    >>> number = -42
    >>> assert number > 0
    Traceback (most recent call last):
        ...
    AssertionError
    
    41 environment variable to an appropriate value.

In this section, you’ll learn how to disable your assertions by using these two techniques. Before doing this, you’ll get to know the built-in

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42 constant, which is the internal mechanism that Python uses to disable assertions.

Understanding the >>> number = 42 >>> assert number > 0 >>> number = -42 >>> assert number > 0 Traceback (most recent call last): ... AssertionError 42 Built-in Constant

Python has a built-in constant called . This constant is closely related to the

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement. Python’s
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42 is a Boolean constant, which defaults to
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
47. It’s a constant because you can’t change its value once your Python interpreter is running:

>>>

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
7

In this code snippet, you first confirm that

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42 is a Python built-in that’s always available for you.
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
47 is the default value of
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42, and there’s no way to change this value once your Python interpreter is running.

The value of

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42 depends on which mode Python runs in, normal or optimized:

ModeValue of

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42Normal (or debug)
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
47Optimized
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
54

Normal mode is typically the mode that you use during development, while optimized mode is what you should use in production. Now, what does

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42 have to do with assertions? In Python, the
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement is equivalent to the following conditional:

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
8

If

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42 is true, then the code under the outer
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
58 statement runs. The inner
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
58 statement checks
number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
9 for truthiness and raises an
number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
2 only if the expression is not true. This is the default or normal Python mode, in which all your assertions are enabled because
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42 is
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
47.

On the other hand, if

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42 is
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
54, then the code under the outer
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
58 statement doesn’t run, meaning that your assertions will be disabled. In this case, Python is running in optimized mode.

Normal or debug mode allows you to have assertions in place as you develop and test the code. Once your current development cycle is complete, then you can switch to optimized mode and disable the assertions to get your code ready for production.

To activate optimized mode and disable your assertions, you can either start up the Python interpreter with the or option, or set the system variable to an appropriate value. You’ll learn how to do both operations in the following sections.

Remove ads

Running Python With the >>> number = 42 >>> assert number > 0 >>> number = -42 >>> assert number > 0 Traceback (most recent call last): ... AssertionError 39 or >>> number = 42 >>> assert number > 0 >>> number = -42 >>> assert number > 0 Traceback (most recent call last): ... AssertionError 40 Options

You can disable all your

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statements by having the
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42 constant set to
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
54. To accomplish this task, you can use Python’s
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
39 or
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
40 command-line options to run the interpreter in optimized mode.

The

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
39 option internally sets
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42 to
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
54. This change removes the
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statements and any code that you’ve explicitly introduced under a conditional targeting
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42. The
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
40 option does the same as
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
39 and also discards docstrings.

Running Python with the

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
39 or
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
40 command-line option makes your compiled smaller. Additionally, if you have several assertions or
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
86 conditionals, then these command-line options can also make your code faster.

Now, what effect does this optimization have on your assertions? It disables them. For an example, open your command line or terminal within the directory containing the

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
87 file and run an interactive session with the
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
88 command. Once there, run the following code:

>>>

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
9

Because the

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
39 option disables your assertions by setting
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42 to
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
54, your
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
13 class now accepts a negative radius, as the final example showcases. This behavior is completely wrong because you can’t have a circle with a negative radius. Additionaly, the circle’s area is computed using the wrong radius as an input.

The potential to disable assertions in optimized mode is the main reason why you must not use

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statements to validate input data but as an aid to your debugging and testing process.

Note: Assertions are typically turned off in production code to avoid any overhead or side effect that they may cause.

A Pythonic solution for the

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
13 class would be to turn the
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
18 attribute into a managed attribute using the
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
96 decorator. This way, you perform the
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
18 validation every time the attribute changes:

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
0

Now

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
18 is a managed attribute that provides setter and getter methods using the
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
96 decorator. You’ve moved the validation code from
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
14 to the setter method, which is called whenever the class changes the value of
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
18.

Now, the updated

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
13 works as expected if you run the code in optimized mode:

>>>

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
1

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
13 always validates the value of
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
18 before assignment, and your class works correctly, raising a
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
05 for negative values of
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
18. That’s it! You’ve fixed the bug with an elegant solution.

An interesting side effect of running Python in optimized mode is that code under an explicit

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
86 condition is also disabled. Consider the following script:

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
2

This script explicitly checks the value of

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42 in an
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
58 …
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
10 statement. The code in the
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
58 code block will run only if
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42 is
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
47. In contrast, if
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42 is
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
54, then the code in the
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
10 block will run.

Now try running the script in normal and optimized mode to check its behavior in each mode:

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
3

When you execute the script in normal mode, the code under the

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
86 condition runs because
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42 is
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
47 in this mode. On the other hand, when you execute the script in optimized mode with the
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
39 option,
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42 changes to
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
54, and the code under the
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
10 block runs.

Python’s

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
39 command-line option removes assertions from the resulting compiled bytecode. Python’s
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
40 option performs the same kind of optimization as
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
39, with the addition of removing docstrings from your bytecode.

Because both options set

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42 to
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
54, any code under an explicit
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
86 conditional also stops working. This behavior provides a powerful mechanism to introduce debugging-only code in your Python projects during their development stages.

Now you know the basics of using Python’s

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
39 and
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
40 options to disable your assertions in production code. However, running Python with either of these options every time you need to run your production code seems repetitive and may be error-prone. To automate the process, you can use the
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
41 environment variable.

Remove ads

Setting the >>> number = 42 >>> assert number > 0 >>> number = -42 >>> assert number > 0 Traceback (most recent call last): ... AssertionError 41 Environment Variable

You can also run Python in optimized mode with disabled assertions by setting the

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
41 environment variable to an appropriate value. For example, setting this variable to a non-empty string is equivalent to running Python with the
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
39 option.

To try

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
41 out, fire up your command line and run the following command:

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
4

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
5

Once you’ve set

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
41 to a non-empty string, you can launch your Python interpreter with the bare-bones
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
38 command. This command will automatically run Python in optimized mode.

Now go ahead and run the following code from the directory containing your

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
87 file:

>>>

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
6

Again, your assertions are off, and the

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
13 class accepts negative radius values. You’re running Python in optimized mode again.

Another possibility is to set

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
41 to an integer value,
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
42, which is equivalent to running Python using the
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
39 option
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
42 times. In other words, you’re using
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
42 levels of optimization:

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
7

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
8

You can use any integer number to set

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
41. However, Python only implements two levels of optimization. Using a number greater than
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
47 has no real effect on your compiled bytecode. Additionally, setting
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
41 to
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
49 will cause the interpreter to run in normal mode.

Running Python in Optimized Mode

When you run Python, the interpreter compiles any imported module to bytecode on the fly. The compiled bytecode will live in a directory called

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
50, which is placed in the directory containing the module that provided the imported code.

Inside

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
50, you’ll find a
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
52 file named after your original module plus the interpreter’s name and version. The name of the
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
52 file will also include the optimization level used to compile the code.

For example, when you import code from

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
87, the Python 3.10 interpreter generates the following files, depending on the optimization level:

File NameCommand

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
41
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
56
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
57
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
49
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
59
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
60
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
61
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
62
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
63
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
47

The name of each file in this table includes the original module’s name (

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
65), the interpreter that generated the code (
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
66), and the optimization level (
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
67). The table also summarizes the corresponding commands and values for the
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
41 variable. PEP 488 provides more context on this naming format for
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
52 files.

The main results of running Python in the first level of optimization is that the interpreter sets

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42 to
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
54 and removes the assertions from the resulting compiled bytecode. These optimizations make the code smaller and potentially faster than the same code running in normal mode.

The second level of optimization does the same as the first level. It also removes all the docstrings from the compiled code, which results in an even smaller compiled bytecode.

Remove ads

Testing Your Code With Assertions

Testing is another field in the development process where assertions are useful. Testing boils down to comparing an observed value with an expected one to check if they’re equal or not. This kind of check perfectly fits into assertions.

Assertions must check for conditions that should typically be true, unless you have a bug in your code. This idea is another important concept behind testing.

The

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
72 third-party library is a popular testing framework in Python. At its core, you’ll find the
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement, which you can use to write most of your test cases in
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
72.

Here are a few examples of writing test cases using

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statements. The examples below take advantage of some built-in functions, which provide the testing material:

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
9

All these test cases use the

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement. Most of them are written using the assertion formats that you learned before. They all showcase how you’d write real-world test cases to check different pieces of your code with
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
72.

Now, why does

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
72 favor plain
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statements in test cases over a custom API, which is what other testing frameworks prefer? There are a couple of remarkable advantages behind this choice:

  • The
    number = 42
    
    assert (
        number > 0 and isinstance(number, int),
        f"number greater than 0 expected, got: {number}"
    )
    
    0 statement allows
    >>> number = 42
    >>> assert number > 0, f"number greater than 0 expected, got: {number}"
    
    >>> number = -42
    >>> assert number > 0, f"number greater than 0 expected, got: {number}"
    Traceback (most recent call last):
        ...
    AssertionError: number greater than 0 expected, got: -42
    
    72 to lower the entry barrier and somewhat flatten the learning curve because its users can take advantage of Python syntax that they already know.
  • The users of
    >>> number = 42
    >>> assert number > 0, f"number greater than 0 expected, got: {number}"
    
    >>> number = -42
    >>> assert number > 0, f"number greater than 0 expected, got: {number}"
    Traceback (most recent call last):
        ...
    AssertionError: number greater than 0 expected, got: -42
    
    72 don’t need to import anything from the library to start writing test cases. They only need to start importing things if their test cases get complicated, demanding more advanced features.

These advantages make working with

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
72 a pleasant experience for beginners and people coming from other testing frameworks with custom APIs.

For example, the standard-library

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
84 module provides an API consisting of a list of that work pretty much like
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statements. This kind of API can be difficult to learn and memorize for developers starting with the framework.

You can use

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
72 to run all the test case examples above. First, you need to install the library by issuing the
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
88 command. Then you can execute
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
89 from the command-line. This latter command will display an output similar to the following:

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
0

The first highlighted line in this output tells you that

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
72 discovered and ran eight test cases. The second highlighted line shows that seven out of eight tests passed successfully. That’s why you get seven green dots and an
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
91.

Note: To avoid issues with

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
72, you must run your Python interpreter in normal mode. Remember that optimized mode disables assertions. So, make sure that you’re not running Python in optimized mode.

You can check the current value of your

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
93 environment variable by running the following command:

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
1

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
2

If

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
41 is set, then this command’s output will display its current value.

A remarkable feature to note is that

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
72 integrates nicely with the
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement. The library can display error reports with detailed information about the failing assertions and why they’re failing. As an example, check out the the lines starting with the
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
97 letter in the above output. They display error messages.

Those lines clearly uncover the root cause of the failure. In this example,

>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
98 returns
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
99 instead of
>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
00, which is intentionally wrong. You can use to handle code that is .

Understanding Common Pitfalls of number = 42 assert ( number > 0 and isinstance(number, int), f"number greater than 0 expected, got: {number}" ) 0

Even though assertions are such a great and useful tool, they have some downsides. Like any other tool, assertions can be misused. You’ve learned that you should use assertions mainly for debugging and testing code during development. In contrast, you shouldn’t rely on assertions to provide functionality in production code, which is one of the main drivers of pitfalls with assertions.

In particular, you may run into pitfalls if you use assertions for:

  • Processing and validating data
  • Handling errors
  • Running operations with side effects

Another common source of issues with assertions is that keeping them enabled in production can negatively impact your code’s performance.

Finally, Python has assertions enabled by default, which can confuse developers coming from other languages. In the following sections, you’ll learn about all these possible pitfalls of assertions. You’ll also learn how to avoid them in your own Python code.

Remove ads

Using number = 42 assert ( number > 0 and isinstance(number, int), f"number greater than 0 expected, got: {number}" ) 0 for Data Processing and Validation

You shouldn’t use

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statements to verify the user’s input or any other input data from external sources. That’s because production code typically disables assertions, which will remove all the verification.

For example, suppose you’re building an online store with Python, and you need to add functionality to accept discount coupons. You end up writing the following function:

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
3

Notice the

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement in the first line of
>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
06? It’s there to guarantee that the discounted price won’t be equal to or lower than zero dollars. The assertion also ensures that the new price won’t be higher than the product’s original price.

Now consider the example of a pair of shoes at twenty-five percent off:

>>>

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
4

All right,

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
06 works nicely! It takes the product as a dictionary, applies the intended discount to the current price, and returns the new price. Now, try to apply some invalid discounts:

>>>

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
5

Applying an invalid discount raises an

number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
2 that points out the violated condition. If you ever encounter this error while developing and testing your online store, then it shouldn’t be hard to figure out what happened by looking at the traceback.

The real problem with the example above comes if the end user can make direct calls to

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
06 in production code with disabled assertions. In this situation, the function won’t check the input value for
>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
10, possibly accepting wrong values and breaking the correctness of your discount functionality.

In general, you can write

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statements to process, validate, or verify data during development. However, if those operations remain valid in production code, then make sure to replace them with an
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
58 statement or a
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
6 …
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
7 block.

Here’s a new version of

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
06 that uses a conditional instead of an assertion:

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
6

In this new implementation of

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
06, you replace the
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement with an explicit conditional statement. The function now applies the discount only if the input value is between
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
49 and
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
61. Otherwise, it raises a
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
05, signaling the problem.

Now you can wrap up any calls to this function in a

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
6 …
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
7 block that catches the
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
05 and sends an informative message to the users so that they can take action accordingly.

The moral of this example is that you shouldn’t rely on the

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement for data processing or data validation, because this statement is typically turned off in production code.

Handling Errors With number = 42 assert ( number > 0 and isinstance(number, int), f"number greater than 0 expected, got: {number}" ) 0

Another important pitfall with assertions is that sometimes developers use them as a quick form of error handling. As a result, if the production code removes assertions, then important error checks are also removed from the code. So, keep in mind that assertions aren’t a replacement for good error handling.

Here’s an example of using assertions for error handling:

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
7

If you execute this code in production with disabled assertions, then

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
26 will never run the
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement and raise an
number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
2. In this situation, the
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
6 …
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
7 block is superfluous and nonfunctional.

What can you do to fix this example? Try updating

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
26 to use an
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
58 statement and a
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
05:

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
8

Now

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
26 deals with the condition by using an explicit
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
58 statement that can’t be disabled in production code. Your
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
6 …
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
7 block now handles a
>>> number = 42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"

>>> number = -42
>>> assert number > 0, f"number greater than 0 expected, got: {number}"
Traceback (most recent call last):
    ...
AssertionError: number greater than 0 expected, got: -42
05, which is a more appropriate exception in this example.

Don’t ever catch

number = 42

assert number > 0 and isinstance(number, int), \
    f"number greater than 0 expected, got: {number}"
2 exceptions in your code, because that would silence failing assertions, which is a clear sign of misused assertions. Instead, catch concrete exceptions that are clearly related to the errors that you’re handling and let your assertions fail.

Use assertions only to check errors that shouldn’t happen during the normal execution of your programs unless you have a bug. Remember that assertions can be disabled.

Remove ads

Running number = 42 assert ( number > 0 and isinstance(number, int), f"number greater than 0 expected, got: {number}" ) 0 on Expressions With Side Effects

Another subtle pitfall with the

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement appears when you use this statement to check operations, functions, or expressions that have some kind of side effect. In other words, these operations modify the state of objects outside the operation’s scope.

In those situations, the side effect takes place every time your code runs the assertion, which might silently change your program’s global state and behavior.

Consider the following toy example, in which a function modifies the value of a global variable as a side effect:

>>>

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
9

In this example,

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
42 returns
>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
43 at a given
>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
44 in the input
>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
45 of data, with the side effect of also removing said
>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
43.

Using assertions to make sure that your function is returning the correct item can seem appropriate. However, this will cause the function’s internal side effect to run in every assertion, modifying the original content of

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
45.

To prevent unexpected behaviors like the one in the above example, use assertion expressions that don’t cause side effects. For example, you can use pure functions that just take input arguments and return the corresponding output without modifying the state of objects from other scopes and namespaces.

Impacting Performance With number = 42 assert ( number > 0 and isinstance(number, int), f"number greater than 0 expected, got: {number}" ) 0

Too many assertions in production can impact your code’s performance. This issue becomes critical when the asserted conditions involve too much logic, such as long compound conditions, long-running predicate functions, and implying a costly instantiation process.

Assertions can impact your code’s performance in two main ways. They will:

  1. Take time to execute
  2. Use extra memory

An

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement that checks for a
number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
4 value can be relatively inexpensive. However, more complex assertions, especially those running heavy code, can measurably slow down your code. Assertions also consume memory to store their own code and any required data.

To avoid performance issues in production code, you should use Python’s

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
39 or
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
40 command-line options or set the
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
41 environment variable according to your needs. Either strategy will optimize your code by generating an assertions-free compiled bytecode, which will run more quickly and take up less memory.

Additionally, to prevent performance issues during development, your assertions should be fairly slim and to the point.

Having number = 42 assert ( number > 0 and isinstance(number, int), f"number greater than 0 expected, got: {number}" ) 0 Statements Enabled by Default

In Python, assertions are enabled by default. When the interpreter runs in normal mode, the

>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
42 variable is
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
47, and your assertions are enabled. This behavior makes sense because you typically develop, debug, and test your code in normal mode.

If you want to disable your assertions, then you need to do it explicitly. You can either run the Python interpreter with the

>>> number = 42

>>> assert(number > 0, f"number greater than 0 expected, got: {number}")
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
57 or
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
40 options, or set the
>>> number = 42
>>> assert number > 0

>>> number = -42
>>> assert number > 0
Traceback (most recent call last):
    ...
AssertionError
41 environment variable to a proper value.

In contrast, other programming languages have assertions disabled by default. For example, if you’re coming into Python from Java, you may assume that your assertions won’t run unless you explicitly turn them on. This assumption can be a common source of confusion for Python beginners, so keep it in mind.

Conclusion

Now you know how to use Python’s

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement to set sanity checks throughout your code and make sure that certain conditions are and remain true. When any of these conditions fail, you have a clear indication of what’s happening. This way, you can quickly debug and fix your code.

The

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement is pretty handy when you need to document, debug, and test your code during the development stages. In this tutorial, you learned how to use assertions in your code and how they can make your debugging and testing process more efficient and straightforward.

In this tutorial, you learned:

  • What assertions are and when to use them
  • How Python’s
    number = 42
    
    assert (
        number > 0 and isinstance(number, int),
        f"number greater than 0 expected, got: {number}"
    )
    
    0 statement works
  • How
    number = 42
    
    assert (
        number > 0 and isinstance(number, int),
        f"number greater than 0 expected, got: {number}"
    )
    
    0 is handy for documenting, debugging, and testing code
  • How assertions can be disabled to improve performance in production
  • What common pitfalls you can face when using
    number = 42
    
    assert (
        number > 0 and isinstance(number, int),
        f"number greater than 0 expected, got: {number}"
    )
    
    0 statements

With this knowledge on the

number = 42

assert (
    number > 0 and isinstance(number, int),
    f"number greater than 0 expected, got: {number}"
)
0 statement, you can now write robust, reliable, and less buggy code, which can take you to the next level as a developer.

Free Download: Get a sample chapter from Python Tricks: The Book that shows you Python’s best practices with simple examples you can apply instantly to write more beautiful + Pythonic code.

Mark as Completed

🐍 Python Tricks 💌

Get a short & sweet Python Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team.

Cara menggunakan assert if python

Send Me Python Tricks »

About Leodanis Pozo Ramos

Cara menggunakan assert if python
Cara menggunakan assert if python

Leodanis is an industrial engineer who loves Python and software development. He's a self-taught Python developer with 6+ years of experience. He's an avid technical writer with a growing number of articles published on Real Python and other sites.

» More about Leodanis


Each tutorial at Real Python is created by a team of developers so that it meets our high quality standards. The team members who worked on this tutorial are:

Cara menggunakan assert if python

Aldren

Cara menggunakan assert if python

Bartosz

Cara menggunakan assert if python

Dan

Cara menggunakan assert if python

Geir Arne

Cara menggunakan assert if python

Kate

Master Real-World Python Skills With Unlimited Access to Real Python

Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:

Level Up Your Python Skills »

Master Real-World Python Skills
With Unlimited Access to Real Python

Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:

Level Up Your Python Skills »

What Do You Think?

Rate this article:

Tweet Share Share Email

What’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know.

Commenting Tips: The most useful comments are those written with the goal of learning from or helping out other students. and get answers to common questions in our support portal.

Apa fungsi dari kode AssertTrue pada python?

6. AssertTrue, untuk mengetahui bahwa value bernilai sesuai dengan yang di harapkan.

Kapan bahasa pemrograman Python dirilis?

Python adalah bahasa pemrograman tujuan umum yang ditafsirkan, tingkat tinggi. Dibuat oleh Guido van Rossum dan pertama kali dirilis pada tahun 1991, filosofi desain Python menekankan keterbacaan kode dengan penggunaan spasi putih yang signifikan.