Exception as the primary error handling mechanism?

Dave Angel davea at ieee.org
Tue Jan 5 10:34:56 EST 2010


r0g wrote:
> Dave Angel wrote:
>   
>> r0g wrote:
>>     
>>> <snip>
>>>
>>> Maybe, although I recently learned on here that one can't rely on assert
>>>  statements in production code, their intended use is to aid debugging
>>> and testing really.
>>>
>>>   
>>>       
>> Hopefully, what you learned is that you can't use assert() in production
>> code to validate user data.  It's fine to use it to validate program
>> logic, because that shouldn't still need testing in production.
>>
>> <snip>
>>
>> DaveA
>>     
>
>
>
> Well maybe I didn't quite get it then, could you explain a bit further?
>
> My understanding was that asserts aren't executed at all if python is
> started with the -O or -OO option, or run through an optimizer. If
> that's the case how can you expect it to validate anything at all in
> production? Do you mean for debugging in situ or something? Could you
> maybe give me an example scenario to illustrate your point?
>
> Cheers,
>
> Roger.
>
>   
You understand the -O and -OO options fine.  But the point is that you 
should not use assert() for anything that will be properly debugged 
before going to the user.  You use if statements, and throw's to catch 
the error, and print to stderr, or GUI dialog boxes, or whatever 
mechanism you use to tell your user.  But those errors are ones caused 
by his data, not by your buggy code.  And the message tells him what's 
wrong with his data, not that you encountered a negative value for some 
low level function.

I agree with Steve's pessimistic view of the state of most released 
software.  But if you view a particular internal check as useful for 
production, then it should be coded in another mechanism, not in 
assert.  Go ahead and write one, with a UI that's appropriate for your 
particular application.  But it should do a lot more than assert does, 
including telling the user your contact information to call for support.

            def production_assert(expression, message):
                         if  not expression:
                                   dialog_box("Serious internal bug, 
call  NNN-NNN-NNNN immediately", message)


For an overly simplified example showing a user validation, and an assert :

import sys
def main():
    try:
        text = raw_input("Enter your age, between 1 and 22 ")
        age = int(text)
    except  ValueError, e:
        age = -1
    if not 1 <= age <= 22:             #not an assert
        print "Age must be between 1 and 22"
        print "Run program again"
        sys.exit(2)
    grade = calc_grade(age)
    print "Your grade is probably", grade

table = [0, 0, 0, 0, 0, "K", "First", "2nd", 3]
def calc_grade(age):
    """ calculate a probable grade value, given an
    i2nteger age between 1 and 22, inclusive
    """
    assert(1 <= age <= len(table))
    grade = table[age]    #assume I have a fixed-length table for this
    return grade

main()

Note a few things.  One I have a bug, in that the table isn't as big as 
the limit I'm checking for.  With defensive coding, I'd have another 
assert for that, or even have the table size be available as a global 
constant (all uppers) so that everyone's in synch on the upper limit.  
But in any case, the test suite would be checking to make sure the code 
worked for 1, for 22, for a couple of values in between, and that a 
proper error response happened when a non-integer was entered, or one 
outside of the range.  That all happens in separate code, not something 
in this file.  And the test suite is run after every change to the 
sources, and certainly before release to production.

Next, see the docstring.  It establishes a precondition for the 
function.  Since the function is called only by me (not the user), any 
preconditions can be checked with an assert.  An assert without a 
supporting comment (or docstring) is almost worthless.

And finally, notice that I check the user's input *before* passing it on 
to any uncontrolled code.  So any asserts after that cannot fire, unless 
I have a bug which was not caught during testing.

All opinions my own, of course.

DaveA




More information about the Python-list mailing list