r0g said:
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