Sometimes when I look at other people's code I see functions that make a bunch of assumptions about the inputs but do not explicitly assert
their assumptions. For example, look at the code below:
def func(a: list, b: list, c: int):
total = 0
for i in range(len(a)):
total = a[i] + b[i]
return total/c
My first instinct when I see code like this is to add a bunch of assert
statements, like so:
def func(a: list, b: list, c: int):
assert len(a) <= len(b)
assert c, "cannot be 0"
total = 0
for i in range(len(a)):
total = a[i] + b[i]
return total/c
My argument is that I would much rather get an AssertionError
so I know the exact problem (especially if there's a useful message) than an IndexError
or something else and then have to figure out what the root cause is. Sometimes I see 5 or 6 assumptions made about the input, but in practice I don't see functions starting with lots of assert
statements very often. I'm tempted to add a bunch of asserts to some code I found to make debugging easier. Is there any reason not to do this?
EDIT:
Another way of asking this is if I get an error while running code and debug it to realize that input x
from two calls higher in the traceback should always have some property (e.g. always be positive), is there any reason not to just add an assert
statement right away in the code?
EDIT2:
Here's an example from a popular code repo. In this case, the argument direction
has to be in range(8)
. If it is not, the user gets an error that says
Exception has occurred: UnboundLocalError
local variable 'targ_pts' referenced before assignment
To me, this is much harder to debug than if it started with an assert statement like assert direction in range(8), "skew direction must be integer between 0 and 7"
. Should an assert statement be added in this case?
if len(a) != len(b): raise ValueError("a and b should be same length")
andif c == 0: raise ValueError("c cannot be 0")
, in this case. Cross-site dupe: stackoverflow.com/questions/944592/….