Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Proper way to handle errors in a module

52 views
Skip to first unread message

Andrew Berg

unread,
May 11, 2011, 1:29:50 PM5/11/11
to pytho...@python.org
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.

Patty

unread,
May 11, 2011, 1:57:49 PM5/11/11
to Andrew Berg, pytho...@python.org

> --
> http://mail.python.org/mailman/listinfo/python-list
>
>

Hi Andrew -

Sometimes you want an exception come up and then use that information to
take your
program in some direction. For example, you might want your program to
'see' the exception
that comes up when you go one beyond the end of an array. This means that
something you
wanted to happen within the array you set up finished successfully (the
program just reached one
beyond it and you didn't get an error!). The enduser doesn't need to see
this displayed on the screen
or in a window, you can just use an exception as-is to your advantage within
the program.

Regards,

Patty

Roy Smith

unread,
May 11, 2011, 2:05:09 PM5/11/11
to
In article <mailman.1415.1305134...@python.org>,
Andrew Berg <bahamut...@gmail.com> wrote:

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.

MRAB

unread,
May 11, 2011, 2:08:57 PM5/11/11
to pytho...@python.org
On 11/05/2011 18:29, Andrew Berg wrote:
> 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.

Generally speaking, a function or method should either do what it's
expected to do, returning the expected result, or raise an exception if
it can't.

Also, it's often clearer to distinguish between a function, which
returns a result, and a procedure, which doesn't (in Python it would
return None).

For example, if you have a list, the functional form is:

sorted(my_list)

which returns a new sorted list, and the procedural form is:

my_list.sort()

which sorts in-place (modifying the list) and returns None.

Andrew Berg

unread,
May 11, 2011, 2:14:39 PM5/11/11
to pytho...@python.org
On 2011.05.11 12:57 PM, Patty wrote:
> Hi Andrew -
>
> Sometimes you want an exception come up and then use that information to
> take your
> program in some direction.
Right, but I'm wondering how I should handle errors in a module, where
different people will want their programs to do different things when an
error occurs in a function or method from my module (which is not
necessarily because of a bug in my module - the calling script could
send a bad parameter or some system configuration could prevent the
function from doing something). On one hand, I could let almost all
exceptions go unhandled and have the calling script handle them. This
would force the developer of the calling script to learn all the
exceptions that my module could raise (which could be really annoying if
I have custom exceptions for problems that don't otherwise raise an
exception). OTOH, I could handle all the exceptions and return None or
some default value, but that would make it harder for the developer to
make the script react appropriately.

Prasad, Ramit

unread,
May 11, 2011, 2:50:00 PM5/11/11
to Andrew Berg, pytho...@python.org
The simple but code heavy system is to create two functions. One that raises an error and one that returns None or something that is mutually agreed to be invalid. You can even get away with one of them doing the actual work and the other one just as a wrapper. I feel too lazy to fix the mistakes below, but you get the idea.

Def a():
Blahblah
Raise SomeError

Def b():
Try:
A()
Except SomeError:
Return blah


Ramit



Ramit Prasad | JPMorgan Chase Investment Bank | Currencies Technology
712 Main Street | Houston, TX 77002
work phone: 713 - 216 - 5423
--
http://mail.python.org/mailman/listinfo/python-list
This communication is for informational purposes only. It is not
intended as an offer or solicitation for the purchase or sale of
any financial instrument or as an official confirmation of any
transaction. All market prices, data and other information are not
warranted as to completeness or accuracy and are subject to change
without notice. Any comments or statements made herein do not
necessarily reflect those of JPMorgan Chase & Co., its subsidiaries
and affiliates.

This transmission may contain information that is privileged,
confidential, legally privileged, and/or exempt from disclosure
under applicable law. If you are not the intended recipient, you
are hereby notified that any disclosure, copying, distribution, or
use of the information contained herein (including any reliance
thereon) is STRICTLY PROHIBITED. Although this transmission and any
attachments are believed to be free of any virus or other defect
that might affect any computer system into which it is received and
opened, it is the responsibility of the recipient to ensure that it
is virus free and no responsibility is accepted by JPMorgan Chase &
Co., its subsidiaries and affiliates, as applicable, for any loss
or damage arising in any way from its use. If you received this
transmission in error, please immediately contact the sender and
destroy the material in its entirety, whether in electronic or hard
copy format. Thank you.

Please refer to http://www.jpmorgan.com/pages/disclosures for
disclosures relating to European legal entities.

Andrew Berg

unread,
May 12, 2011, 3:14:22 PM5/12/11
to pytho...@python.org
On 2011.05.11 01:05 PM, Roy Smith wrote:
> 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.

MRAB

unread,
May 12, 2011, 3:25:21 PM5/12/11
to pytho...@python.org
On 12/05/2011 20:14, Andrew Berg wrote:
> On 2011.05.11 01:05 PM, Roy Smith wrote:
>> 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! :-)

Andrew Berg

unread,
May 12, 2011, 4:12:39 PM5/12/11
to pytho...@python.org
On 2011.05.12 02:25 PM, MRAB wrote:
> 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.

Corey Richardson

unread,
May 12, 2011, 4:20:13 PM5/12/11
to pytho...@python.org
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

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-----

Tycho Andersen

unread,
May 12, 2011, 4:26:27 PM5/12/11
to Andrew Berg, pytho...@python.org
On Thu, May 12, 2011 at 03:12:39PM -0500, Andrew Berg wrote:
> On 2011.05.12 02:25 PM, MRAB wrote:
> > 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.

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.
>>> class HelloError(Exception): pass
...
>>> raise HelloError("hello!")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
__main__.HelloError: hello!

\t

MRAB

unread,
May 12, 2011, 4:26:55 PM5/12/11
to pytho...@python.org
On 12/05/2011 21:12, Andrew Berg wrote:
> On 2011.05.12 02:25 PM, MRAB wrote:
>> 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.

Define it as a subclass of Exception:

class UnknownBirdError(Exception):
pass

Ethan Furman

unread,
May 12, 2011, 4:40:44 PM5/12/11
to Andrew Berg, pytho...@python.org
Andrew Berg wrote:
> On 2011.05.12 02:25 PM, MRAB wrote:
>> 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.

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~

Andrew Berg

unread,
May 12, 2011, 4:35:16 PM5/12/11
to pytho...@python.org
On 2011.05.12 03:20 PM, Corey Richardson wrote:
> 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
So that's where that info is. I wasn't looking in the tutorial section.
Thanks!

Steven D'Aprano

unread,
May 12, 2011, 8:43:06 PM5/12/11
to
On Thu, 12 May 2011 15:26:27 -0500, Tycho Andersen wrote:

> On Thu, May 12, 2011 at 03:12:39PM -0500, Andrew Berg wrote:
>> On 2011.05.12 02:25 PM, MRAB wrote:
>> > 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.
>
> 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.

>>> raise 42


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!

>>> isinstance(42, int)
True

In Python 3, you get a better error message, and further restrictions on
what you can raise:

>>> raise 42


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.


--
Steven

Ben Finney

unread,
May 12, 2011, 8:56:14 PM5/12/11
to
Andrew Berg <bahamut...@gmail.com> writes:

> So that's where that info is. I wasn't looking in the tutorial
> section.

Does this mean you haven't worked through the tutorial? Time to remedy
that.

--
\ “You are welcome to visit the cemetery where famous Russian and |
`\ Soviet composers, artists, and writers are buried daily except |
_o__) Thursday.” —Russian orthodox monastery, Moscow |
Ben Finney

0 new messages