When we talked about try…except, I thought back to my personal project last semester after taking 108: Coursegrade. (If you’re going to download it, avoid the Mac application. It doesn’t work. And I rarely have access to a Mac, which means I can’t compile it right now. Just grab the source… but hey, it is a good program, I promise!)
I wanted to do two things when allowing people to enter various inputs into the program: it had to be a valid input and it had to be sorted properly. Regarding the sorting, for example, I wanted to let people enter the grade they received on an assignment, and rather than bothering them with having to choose “percent” or “fraction”, I wanted the program to figure it out for them. The program takes several different inputs (the functions I have for checking input are valid_number, valid_letter, valid_fraction, and valid_string),
I looked up how I could easily handle a lot of different requirements. Boy, handling valid input is complicated. At first I had a ton of if…else checks, but it got so complicated that I couldn’t even keep track of all the different things that could go wrong with someone entering a fraction string. Then I found a reference to try…except somewhere on Stack Overflow and decided it could help me.
So, without further ado, here are some excerpts in case other learners can benefit.
First, the very simple valid_number:
def valid_number(s): try: number = float(s) return True except: return False
The functionality is clear: it’s going to try to float the input. If it’s possible to convert it to a float, this is a valid number. If that attempt raised an error, it’s not.
Here’s the second example. I thought this was a slightly more innovative use of try…except. The background is that the program saves your data in a text file. This data consists of profiles, which primarily contain courses, which primarily contain assignments, which primarily contain weights and grades. These are all classes. Whenever you open up the program, it looks for a save file, reads everything, and instantiates a single object: a class that (for some strange reason) I called “Runtime”. Then it calls the program’s all-encapsulating function, main_menu, passing it this object as a parameter.
Now, when do we save the data? I thought of including a button on every menu called “save”, but decided against it. Instead, I decided to basically save everything you do and make it unavoidable (for simplicity’s sake and to avoid you forgetting to save). I’ll probably change this if I make a new version, but the result was a “Save & Exit” button. So the question was: how do I make this implementation as simple and elegant as possible? After all, my program is structured as a set of nested menu functions running on while loops until you close them. I’d have to use break multiple times to get out quickly.
Well, here was my solution, four of the only five lines in __main__:
try: main_menu(runtime) except(SystemExit): file_save(FILENAME, runtime)
I saw that there was an exception class called SystemExit, which seems to be called only when you intentionally call the function exit() from the sys module. Since I could control exactly when this “error” was raised, I was able to use it strategically. The whole program is run in a try block. Each “Save & Exit” button has only one effect: it calls exit(). (If I had learned what we learned this week, I would have known I could just use a raise statement.) The SystemExit exception that’s raised isn’t caught by any of the handlers on the way up, so it gets handled by the except block here, which will take this as a cue to save the file. Note that no other errors will be caught, and therefore no other errors will save the file. Normally, if an unexpected error is encountered, the data is going to be messed up in some way, so I only wanted it to be saved when everything’s going well and the user intentionally saves and quits.
So there you go! Two easy uses of try…except, one where we’re catching an expected error and one where we raise it ourselves as a way of backing our way out of a lot of nested functions in a quick and controlled way. Hope this has been useful!