I've read many questions and articles on exception handling in Python (and in general), but I still think that it's the most confusing thing ever. I ended up doing something like this:
# error class for exceptions specific to this script
class MyError(Exception): pass
# error class for exceptions in MyClass,
# which can be used from outside of this script
class MyClassError(Exception): pass
class MyClass:
...
# class has method that takes a function as a parameter
def method(self, param_function):
...
param_function(a, b, c, d)
try:
some_other_funtion(arg)
except ValueError, e:
raise MyClassError("Some message")
...
# outside of MyClass
if __name__ == "__main__":
# read input from console etc.
# ...
def function(a, b, c, d):
# ....
try:
# something with a
except ValueError, e:
raise MyError("My message:" + a)
try:
# something with b
except ValueError, e:
raise MyError("My message:" + b)
try:
# something with c
except ValueError, e:
raise MyError("My message:" + c)
try:
# something with d
except ValueError, e:
raise My Error("My slightly different message:" + d)
x = MyClass()
try:
x.method(function)
except (IOError, MyError, MyClassError) as e:
print e
Explanation:
I want the user of the script to just get a user-friendly message if the error is a result of him passing the wrong input.
The messages with which I raise my custom exceptions are user-friendly, and they (in my opinion) contain all the information I want the user to see.
That's also the reason why I'm handling IOError in a similar manner. I expect an IOError only if the user provides a wrong filename, and I want him to see something like "File not found: name of the file" and nothing more.
Why this seems wrong:
In my main function, in function
, I'm basically surrounding every line of code with a try-catch, and handling every exception in a similar manner – sometimes the message the user should see is a little different, but mostly the only difference is the parameter in the message.
Questions:
Am I handling my exceptions in the right places?
Am I handling them in the right way?
Is the code duplication that I'm doing in function
neccessary?
Best Answer
User input sucks. You can't trust those users to get anything right, and so you've got to handle all kinds of special cases that make your life difficult. Having said that, we can minimize the difficulty with general principles.
Validate early, not often
Check input for validity as soon as it read into your program. If you read in a string that should be a number, convert it into a number right away and complain to the user if it isn't a number. Any rogue data you don't verify at input will make its way into the rest of the program and produce bugs.
Now, you can't always do this. There will be cases where you can't verify the correct properties right away, and you'll have to verify them during later processing. But you want as much verification to happen as early as possible so that you have your special cases around input logic centralized to one location as much as possible.
Use Schemas
Let's consider a function that parses some json.
That was a lot of work just to extract the first name, let alone any other attributes. We can make this a lot better if we can use a json-schema. See: http://json-schema.org/.
I can describe what my student object looks like:
When I parse I then do something like:
Checking against the schema verifies must of the structure that I need. If the user input failing the schema, the schema validator will produce a nice error message explaining exactly what was wrong. It will do so far more consistently and correctly then if I wrote the checking code by hand. Once the validation has been passed, I can just grab data out of the json object, because I know that it will have the correct structure.
Now, you probably aren't parsing JSON. But you may find that you can do something similar for your format that lets you reuse the basic validation logic across the different pieces of information that you fetch.