[Tutor] Code evaluation inside of string fails with __get_item
Steven D'Aprano
steve at pearwood.info
Sun Dec 12 03:18:44 CET 2010
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
More information about the Tutor
mailing list