[Tutor] Terminology question

Steven D'Aprano steve at pearwood.info
Sat May 16 08:04:17 CEST 2015


On Thu, May 14, 2015 at 03:43:30PM -0700, Jim Mooney Py3.4.3winXP wrote:
> I noticed that if I call a function that throws an error, I can catch it
> from the caller, instead of catching it in the function. Is this is what is
> known as "errors bubbling up?" Also, is this how you're supposed to do it?

Consider a chain of functions:

main() calls setup();
setup() calls process_arguments();
process_arguments() calls read_config();
read_config() calls open("somefile");

and open("somefile") raises an exception (perhaps the file cannot be 
found, or you don't have permission to read it).


Each function in the chain gets a chance to catch the exception:

open <- read_config <- process_arguments <- setup <- main


If open doesn't catch the exception, we say that the exception "bubbles 
up" the chain until it is caught, or if none of them catch it, then it 
bubbles all the way up and finally reaches the Python interpreter, which 
prints a stack trace and exits.


[...]
> def get_input():
>     inp = input("Enter minimum, maximum, rows, and columns, separated by
> commas: ")
>     inps = inp.split(',')
>     try:
>         minimum = int(inps[0])
>         maximum = int(inps[1])
>         rows = int(inps[2])
>         columns = int(inps[3])
>         return minimum, maximum, rows, columns

This is not best practice. There are too many things which might cause 
an exception. Ideally, a try block should only contain *one* thing which 
might go wrong. Here you have at least four. By treating them all the 
same, you lose the opportunity to give the user information about 
*which* one they screwed up.


>     except ValueError as err:
>         print("non-integer entered", err)
>         return None

This is bad practice, for two reasons.

You might not think so yet, but Python tracebacks give you a lot of 
useful debugging information. Here, you flush that useful information 
down the toilet and replace it with a not-very helpful message 
"non-integer entered" (plus a bit more stuff). In a trivial script that 
might not matter, but in a big script, you may have *no idea* where this 
non-integer was entered. There could be thirty places where it might 
happen. How do you know which one it is?

The second reason is that you really should only catch exceptions that 
you can do something about. If you can't fix the problem, there's no 
point in catching the exception[1]. In this case, if the user doesn't 
enter a valid set of values, there's no way you can proceed. So why 
bother delaying the inevitable? Just let the exception exit the program.

This will also look after all the little things which distinguish a 
professional quality application from a jerry-built beginner's toy. For 
example: error messages should print to stderr, not stdout; the 
application should exit with a non-zero result code. If this means 
nothing to you, don't be too concerned about it, just understand that 
Python will do the right thing provided you don't get in its way, as you 
just did by catching the exception.





[1] Well, there is one other reason: in an application aimed at 
non-programmers, you might choose to catch the exception, log the 
traceback somewhere where you can get to it for debugging, and display a 
"friendly" (i.e. non-technical, non-threatening, useless) message to the 
user. But as a beginner yourself, you shouldn't do this until you have 
become an expert in reading tracebacks. Otherwise you're just hiding 
debugging info that you need.


-- 
Steve


More information about the Tutor mailing list