What are acceptable use-cases for python's `assert` statement?

Viewed 11342

I often use python's assert statement to check user input and fail-fast if we're in a corrupt state. I'm aware that assert gets removed when python with the -o(optimized) flag. I personally don't run any of my apps in optimized mode, but it feels like I should stay away from assert just in-case.

It feels much cleaner to write

assert filename.endswith('.jpg')

than

if not filename.endswith('.jpg'):
    raise RuntimeError

Is this a valid use case for assert? If not, what would a valid use-case for python's assert statement be?

8 Answers

Assertions should be used for expressing invariants, or preconditions.
In your example, you are using them for checking unexpected input - and that's a completely different class of exceptions.

Depending on the requirements, it may be perfectly OK to raise an exception on wrong input, and stop the application; however the code should always be tailored for expressiveness, and raising an AssertionError is not that explicit.
Much better would be to raise your own exception, or a ValueError.

If being graceful is impossible, be dramatic

Here is the correct version of your code:

if filename.endswith('.jpg'):
    # convert it to the PNG we want
    try:
        filename = convert_jpg_to_png_tmpfile(filename)
    except PNGCreateError:
        # Tell the user their jpg was crap
        print "Your jpg was crap!"

It is a valid case, IMHO when:

  1. The error is totally, 100% fatal, and dealing with it would be too grim to comprehend
  2. The assert should only fail if something causes the laws of logic to change

Otherwise, deal with the eventuality because you can see it coming.

ASSERT == "This should never occur in reality, and if it does, we give up"

Of course, this isn't the same as

#control should never get here

But I always do

#control should never get here
#but i'm not 100% putting my money where my mouth
#is
assert(False)

That way I get a nice error. In your example, I would use the if version and convert the file to jpg!

Totally valid. The assertion is a formal claim about the state of your program.

You should use them for things which can't be proven. However, they're handy for things you think you can prove as a check on your logic.

Another example.

def fastExp( a, b ):
    assert isinstance(b,(int,long)), "This algorithm raises to an integer power"
    etc.

Yet another. The final assertion is a bit silly, since it should be provable.

# Not provable, essential.
assert len(someList) > 0, "Can't work with an empty list."
x = someList[]
while len(x) != 0:
    startingSize= len(x)
    ... some processing ...
    # Provable.  May be Redundant.
    assert len(x) < startingSize, "Design Flaw of the worst kind."

Yet another.

def sqrt( x ):
    # This may not be provable and is essential.
    assert x >= 0, "Can't cope with non-positive numbers"
    ...
    # This is provable and may be redundant.
    assert abs( n*n - x ) < 0.00001 
    return n

There are lots and lots of reasons for making formal assertions.

assert is best used for code that should be active during testing when you are surely going to run without -o

You may personally never run with -o but what happens if your code ends up in a larger system and the admin wants to run it with -o?

It's possible that the system will appear to run fine, but there are subtle bugs which have been switched on by running with -o

Personally, I use assert for unexpected errors, or things you don't expect to happen in real world usage. Exceptions should be used whenever dealing with input from a user or file, as they can be caught and you can tell the user "Hey, I was expecting a .jpg file!!"

Related