Proper way to handle errors in a module

A

Andrew Berg

I'm a bit new to programming outside of shell scripts (and I'm no expert
there), so I was wondering what is considered the best way to handle
errors when writing a module. Do I just let exceptions go and raise
custom exceptions for errors that don't trigger a standard one? Have the
function/method return nothing or a default value and show an error
message? I'm sure there's not a clear-cut answer, but I was just
wondering what most developers would expect a module to do in certain
situations.
 
R

Roy Smith

Andrew Berg said:
I'm a bit new to programming outside of shell scripts (and I'm no expert
there), so I was wondering what is considered the best way to handle
errors when writing a module. Do I just let exceptions go and raise
custom exceptions for errors that don't trigger a standard one? Have the
function/method return nothing or a default value and show an error
message? I'm sure there's not a clear-cut answer, but I was just
wondering what most developers would expect a module to do in certain
situations.

In general, raise an exception when there is no valid value that can be
returned from a function. Sometimes it makes more sense to return 0,
None, an empty list, etc. So:

count_vowels("banana") ==> 3
count_vowels("xyzzy") ==> 0 # counting "y" as not a vowel
count_vowels("") ==> 0
count_vowels(None) ==> raises TypeError

You want to raise specific errors. Let's say you've got a function like
this:

def airspeed(swallow):
speeds = {"european": 42,
"african", 196}
return speeds[swallow]

If somebody passes an invalid string, it will raise KeyError as written.
Better to do something like:

def airspeed(swallow):
speeds = {"european": 42,
"african", 196}
try:
return speeds[swallow]
except KeyError:
raise UnknownBirdError(swallow)

This lets somebody catch UnknownBirdError at some higher level and do
something useful. If you let KeyError escape, that's a lot harder to
deal with because it could come from almost anywhere.
 
A

Andrew Berg

You want to raise specific errors. Let's say you've got a function like
this:

def airspeed(swallow):
speeds = {"european": 42,
"african", 196}
return speeds[swallow]

If somebody passes an invalid string, it will raise KeyError as written.
Better to do something like:

def airspeed(swallow):
speeds = {"european": 42,
"african", 196}
try:
return speeds[swallow]
except KeyError:
raise UnknownBirdError(swallow)
Is there any way to do this without purposely setting up the code to
trigger an arbitrary exception if the function can't do its job? That
is, can I raise an UnknownBirdError outside of an except clause, and if
so, how? I can't find much help for doing this in Python 3, even in the
official docs.
 
M

MRAB

You want to raise specific errors. Let's say you've got a function like
this:

def airspeed(swallow):
speeds = {"european": 42,
"african", 196}
return speeds[swallow]

If somebody passes an invalid string, it will raise KeyError as written.
Better to do something like:

def airspeed(swallow):
speeds = {"european": 42,
"african", 196}
try:
return speeds[swallow]
except KeyError:
raise UnknownBirdError(swallow)
Is there any way to do this without purposely setting up the code to
trigger an arbitrary exception if the function can't do its job? That
is, can I raise an UnknownBirdError outside of an except clause, and if
so, how? I can't find much help for doing this in Python 3, even in the
official docs.
You can raise an exception wherever you like! :)
 
A

Andrew Berg

You can raise an exception wherever you like! :)
If I raise an exception that isn't a built-in exception, I get something
like "NameError: name 'HelloError' is not defined". I don't know how to
define the exception.
 
C

Corey Richardson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

If I raise an exception that isn't a built-in exception, I get something
like "NameError: name 'HelloError' is not defined". I don't know how to
define the exception.

class HelloError(Exception):
pass

Of course, there are all sorts of other things you could do with your
exception.

http://docs.python.org/tutorial/errors.html#user-defined-exceptions
- --
Corey Richardson
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNzED9AAoJEAFAbo/KNFvp1uQIAKFaKyD1Q3RL7LGFSmnyRFTK
9XWRH3CSM9mOALccfQ8bUkrquol1fAqhrm4jyOW0scWmsJpRlcb6Rj4HtrmMQOuG
DpsUzEZCTnT9Xk80OeTFbpWWBIVBkxdhCxCl75XAP22o5EjhHpgLyqoqMD+81BKH
5/JWAGRJx/9E4BvNWsxIUhb1jlz+XT4H1XykTE1UUOP0uZneWRJMs7P12WNiL2Ii
HT0hEUhQc1eP1fJ5BqPB/6/B9q/KxTbN55hCq1VwwfRhgbaM4kR7Bekri7QUHGAK
1MKxRa1v+Co59y+ywAIH92L3wky3xNyFrUlFzK4AwYOnwRkVvUWw7vPG1iShE+k=
=2+y6
-----END PGP SIGNATURE-----
 
T

Tycho Andersen

If I raise an exception that isn't a built-in exception, I get something
like "NameError: name 'HelloError' is not defined". I don't know how to
define the exception.

You'll have to define it, as you would anything else (exceptions are
just regular "things"; in fact you can raise anything that's a class
or instance). I typically don't put a whole lot in my exception
classes, though.

point:~/working$ python
Python 2.6.2 (r262:71600, Jun 8 2009, 11:11:42)
[GCC 4.3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.Traceback (most recent call last):
File "<stdin>", line 1, in <module>
__main__.HelloError: hello!

\t
 
M

MRAB

If I raise an exception that isn't a built-in exception, I get something
like "NameError: name 'HelloError' is not defined". I don't know how to
define the exception.

Define it as a subclass of Exception:

class UnknownBirdError(Exception):
pass
 
E

Ethan Furman

Andrew said:
If I raise an exception that isn't a built-in exception, I get something
like "NameError: name 'HelloError' is not defined". I don't know how to
define the exception.

class HelloError(Exception):
"custom exception"

and that's all you need. You can override __init__ to add your own
attributes, etc, if you need to.

~Ethan~
 
S

Steven D'Aprano

You'll have to define it, as you would anything else (exceptions are
just regular "things"; in fact you can raise anything that's a class or
instance).

Not quite.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: exceptions must be classes or instances, not int

Not a very good error message, because 42 is an instance!
True

In Python 3, you get a better error message, and further restrictions on
what you can raise:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: exceptions must derive from BaseException


In general, you should always subclass Exception rather than
BaseException. There are, er, exceptions, but for error-handling you
normally should inherit from Exception directly, or some sub-class like
ValueError, KeyError, etc.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,225
Members
46,815
Latest member
treekmostly22

Latest Threads

Top