Tim Johnson wrote:

  I've never had the occasion to use assert() or any other
  python - shooting tools, any thoughts on that?


Assertions are a great tool, but never ever, under pain of great pain, use assert for testing user input or function arguments.

It's tempting to knock up a quick and dirty function like this:

def spam(n):
    assert n >= 0, "amount of spam must be non-negative"
    do_stuff_with(n)


Beware! This way leads to the Dark Side, or at least to strange and mysterious bugs that will only effect a few of your users and have you scratching your head.

The problem is that if you run Python with optimizations turned on, assertions are disabled. When run with python -O, your error checking disappears:

def spam(n):
    do_stuff_with(n)

Strange and terrible things may now occur, exceptions being the *least* of your worries. Better to write explicit tests and give sensible errors:

def spam(n):
    if n < 0:
        raise ValueError("amount of spam must be non-negative")
    do_stuff_with(n)


If you've ever written a comment like "This can't happen, but if it does, raise an exception", then you've essentially made an assertion. Here's a trivial example:

def spam(s):
    s += " spam spam spam glorious SPAM!!!"
    p = s.find("spam")
    if p < 1:
        # This can never happen!
        raise RuntimeError("Serious internal error #123456")
    do_something_with(p)

This could be written as:

def spam(s):
    s += " spam spam spam glorious SPAM!!!"
    p = s.find("spam")
    assert p >= 1, "Serious internal error #123456"
    do_something_with(p)


Now if you want to speed up your program by skipping all those "can never happen" tests, you can run python -O and the asserts will be compiled out.


Assertions are for testing program logic, not for testing user input. You should assume that the caller should never see your assertions: if the caller ever receives an AssertionError, you have failed. (If they receive a ValueError, or similar, that's *their* fault for passing rubbish input to your function.) Assertions are for making statements about *internal* state.

Having said that, sometimes it's hard to decide what counts as an internal state. Can function arguments ever be internal state? Sometimes I do things like this:

def ham(n):
    if n < 0:
        raise ValueError("amount of ham must be non-negative")
    x = _common(n)
    return "Ham is like spam but not as tasty." + x

def spam(n):
    if n < 0:
        raise ValueError("amount of spam must be non-negative")
    x = _common(n)
    return "Spam, glorious SPAM!!!" + x

def _common(n):
    # Internal function.
    assert n >= 0
    do_stuff_here(n)
    return something

Since _common is an internal function which the caller is not supposed to use directly, I feel it is acceptable to treat the input to _common as an internal state. If the caller wants to mess with my internal functions, they're responsible for whatever horrible things happen.

Another good example of assertions is for checking pre-conditions and post-conditions, particularly post-conditions. Here's a real example: in my stats module, I calculate "r", the Pearson's Correlation Coefficient. It doesn't matter what that means, but what does matter is that the result *must* be between -1 and 1, or else my code has a bug in it. Even though my code is perfectly bug-free *cough*, I end the function with the line:

    assert -1.0 <= r <= 1.0

to ensure that if there is a bug in my code, it will raise an exception rather than return a garbage result. If the user wants to live dangerously, they can run with the optimization flag and skip my assertions.


  I am dealing with a programmatically composed format
  string, that originates from a source (html) file

Since the format string is generated by you, then errors in the format string are your responsibility, and they're an internal detail. Use assertions for checking the format string.

However, the HTML source is not an internal detail (at least I wouldn't expect it to be), it is *user* input, so any checks you do while processing the HTML should not use assertions.



It may be
  1)read from the file external to the object
    and the source string passed into the object at instantiation.
    The composed string is then translated correctly and
        the embedded is evaluated.

Who makes that choice? You, or the caller? If the caller, then any errors that occur are not internal state, and you shouldn't use assert. If you, then it's an internal detail and you can use assert.




--
Steven

_______________________________________________
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor

Reply via email to