# Assertions

assert statements are a useful debugging tool in Python (and other languages). You can insert “sanity check” assertions into your code, and Python will raise an error if they are violated:

import math

def root(x):
# NB: assert is a statement not a function, so we don't call with ()
assert x >= 0, "Positive values only (keep it real!)"
return math.sqrt(x)

print(root(4))
print(root(-4))

2.0

---------------------------------------------------------------------------

AssertionError                            Traceback (most recent call last)

<ipython-input-31-9aef97c90f4b> in <module>()
7
8 print(root(4))
----> 9 print(root(-4))

<ipython-input-31-9aef97c90f4b> in root(x)
3 def root(x):
4     # NB: assert is a statement not a function, so we don't call with ()
----> 5     assert x >= 0, "Positive values only (keep it real!)"
6     return math.sqrt(x)
7

AssertionError: Positive values only (keep it real!)


Assertions make your assumptions explicit, and can be read almost like part of your documentation. In this example, you’re saying, “there’s no way anyone would call this function with a negative value, and it would be a problem if they did so I’d like to know about it.” Assertions can also be better than just placing debugging print statements in your code, since the program halts when an assertion fails.

Assertions should only be used for debugging purposes, not to catch errors at runtime (use Exceptions for that instead). Assertions may be stripped from your code when it is run in optimized modes, so they cannot be relied upon for anything other than debugging.

Assertions also have a connection to Exceptions in Python: under the covers, the implementation of the assert statement simply raises an AssertionError Exception if the assertion test fails. Specifically,

assert expression


translates to

if __debug__:
if not expression: raise AssertionError


## Example

As a preliminary, let’s store information about a graded assignment in a structured way. We could go all out and define a custom Assignment class (perhaps using Python’s new dataclass decorator), and that would be a great choice if we had a lot of attributes or methods to deal with.

On the other end of the complexity spectrum, we could use a simple dictionary:

assignment = {'name': 'MP2 Computational Art', 'grade': 100}


or even just a tuple:

assignment = ('MP2 Computational Art', 100)


Instead I’m going to use a namedtuple (you can also read about them “Goodies” chapter of Think Python), which is almost as simple to use as a tuple but has convenient named fields like a class:

from collections import namedtuple

# Create a new MP2 submission
work = Assignment('MP2 Computational Art', 85)
print(work)

Assignment(name='MP2 Computational Art', grade=85)


Let’s write a function to apply a late penalty according to the course policy and return a new namedtuple. (Quick check: could this function be written as a modifier instead? Why or why not?)

As a “sanity check”, we include an assertion that the adjusted grade is not higher than the original grade or lower than zero:

def late_penalty(assignment, days_late):
"""
Given namedtuple Assignment and number of days_late, return

>>> a1 = Assignment('MP1', 90)
>>> late_penalty(a1, days_late=2)
"""


If your assumptions are met, the assertion has no effect:

work = Assignment('MP2 Computational Art', 85)
late_penalty(work, 1)

Assignment(name='MP2 Computational Art', grade=75)


On the other hand if your assumptions are violated, the assertion triggers an error:

# Late by eleven days -> 110% penalty?
late_penalty(work, 11)

---------------------------------------------------------------------------

AssertionError                            Traceback (most recent call last)

<ipython-input-20-f223a24b907e> in <module>()
1 # Late by eleven days -> 110% penalty
----> 2 late_penalty(work, 11)

<ipython-input-17-f1c3d8902c51> in late_penalty(assignment, days_late)
9     """

AssertionError:


This failed assertion is helpful for debugging, here suggesting that we need to handle the special case of assignments >= 10 days late.

def late_penalty(assignment, days_late):

late_penalty(work, 11)

---------------------------------------------------------------------------

AssertionError                            Traceback (most recent call last)

<ipython-input-22-37f67b3248a3> in <module>()
5
----> 6 late_penalty(work, 11)

<ipython-input-22-37f67b3248a3> in late_penalty(assignment, days_late)
1 def late_penalty(assignment, days_late):
5



But be careful! assert is a statement not a function - adding parentheses will not do what you expect it to:

def late_penalty(assignment, days_late):
# WRONG: Incorrect usage of assert as a "function call" not a statement

<ipython-input-25-817aa1c7abac>:4: SyntaxWarning: assertion is always true, perhaps remove parentheses?

late_penalty(work, 11)

Assignment(name='MP2 Computational Art', grade=-25)

• assert is a statement, not a function, so don’t use ()