[Tutor] Impossible Else as Exception

Steven D'Aprano steve at pearwood.info
Wed Apr 10 01:52:40 CEST 2013


On 10/04/13 05:22, Jordan wrote:
> I want to know what exception should be raised if there is a bug in my code that allows an else statement to be triggered, because the else condition in my code should be impossible, unless there is an error in my code.  What exception should I raise so that if my code is wrong it will raise an exception which will give me a trace back?  Which would be most Pythonic?
>
> Example:
>
> if condition is 1:
>      do something with 1
> elif condition is 2:
>      do something with 2
> else: # Impossible unless the code above is flawed.
>      Raise Exception


The above isn't a great example, because the sample code *is* flawed.
The short reason why it is flawed is this:

You use identity tests (using `is`) instead of equality tests (using
`==`) which makes the above code fragile and dependent on the exact
version and implementation of Python being used. There are two rules
for when to use `is`:

1) Only use `is` when comparing to None;

2) (For everything else) If you have to ask if you should use `is`,
    the answer is No.


As given, your question cannot be answered simply. It depends on the
circumstances. Here are the two most common cases:


1) You're testing data you receive from a user, the caller, or another
part of the program. You know what the data should be, but you can't be
sure that it will be. Here's a toy example:


def func(n):
     """Do something useful. Argument n must be 1 or 2."""
     if n == 1:
         do_this()
     elif n == 2:
         do_that()
     else:
         # Y U No Listen? I told you that n must be 1 or 2!
         ...


So what should I put in place of the dots? The answer depends on the
exact tests being performed, but the two most common cases are:

ValueError, if the argument has the wrong value;

TypeError, if the argument has the wrong type.


In this case, I would go with ValueError:

     else:
          raise ValueError('n must be 1 or 2, not %r' % n)



1) You're testing the *internal logic* of your code. In this case, you're
sure of what the data will be, but out of some tiny lingering doubt that
maybe *you* have made a mistake, you want to check just to be sure. Here
is a toy example:


def spam(n):
     """Returns 'spam' n times. Guarantees to return spam."""
     if n <= 0: n = 1
     return ' '.join(['spam']*n)


def breakfast(hunger=3):
     s = "toast and %s and eggs" % spam(hunger)
     if "spam" in s:  # This should always be true.
         return s
     else:
         # This can never happen!
         raise RuntimeError('no spam in breakfast? yuck!')


So RuntimeError is a good choice for this. But if you are *sure* that
the error condition can *never* happen, but not *absolutely sure* and
you still want to check just in case you're mistaken, then an even
better way to write it is:

def breakfast(hunger=3):
     s = "toast and %s and eggs" % spam(hunger)
     assert "spam" in s, 'no spam in breakfast? yuck!'
     return s



-- 
Steven


More information about the Tutor mailing list