[Tutor] ValueError

Alan Gauld alan.gauld at btinternet.com
Wed May 4 10:57:16 CEST 2011


"Kushal Kumaran" <kushal.kumaran+python at gmail.com> wrote

>> Also you should make the try...except as narrow as possible
>>
>> try:
>> centimeters = float(centimeters)
>> except ValueError as e:
>> print e
>>...
>
> I would have expected it to be the other way.  If you cannot
> reasonable expect to continue after an exception, then the try block
> should extend all the way across the block of code you want to skip.

There are at least 2 schools of thought on the use of try/except.

One says put all of the "happy path" processing in the try block
and handle all exceptions at the end. This is very much the
original ADA style that was envisioned when try/except style
first appeared and also in early C++ texts they recommended
that style.

The other says keep try/except as narrow as possible so
you can localise (and maybe correct!) the error.

Both approaches have merit. The first leads to much more
readable code and that in turn has proven to result in more
reliable code, however the second tends  to be more
practical in real world projects. The problem with the first
approach is that there can be multiple places in a block
raising the same error and then determining the cause in
the except becomes hard. This is especially true when the
block contains calls to functions which may unexpectedly
raise errors that may not be documented in their spec.

On the other hand putting try/except around each line of
code leads to unreadable and unmanageable code.

So a compromise is needed and most programmers
settle for something like an "atomic transaction" style
of block. A short group of lines that does something
meaningful and which needs to pass or fail as a unit.
If we plan to attempt error recovery then it also needs
to only raise any given exception type once. (Or we
need to be prepared to use introspection to determine
the cause). But like most design decisions it is a
compromise solution in either case and the programmer
must decide where to make the trade-off.

As an example, consider the case of reading a set
of config values from a file. We have a choice of
what to do if things go wrong:

a) Just bomb out with an error message saying
we couldn't read the config data

b) On any error set the config data to a set of default
values and continue

c) Detect which value failed and set that to a default
using any other values from the file.

For a and b the open plus all of the read/convert/assign
operations can be done within the try block.
For c we would need a try/except around each
read/convert/assign operation. Style c is probably
the most user friendly, provided there are no complex
dependencies between the config values, but there
is no absolute right or wrong decision it is down to
the designer.

HTH,


-- 
Alan Gauld
Author of the Learn to Program web site
http://www.alan-g.me.uk/




More information about the Tutor mailing list