Best Practices for Python Exceptions?

PythonException

Python Problem Overview


What are the best practices for creating exceptions? I just saw this, and I don't know if I should be horrified, or like it. I read several times in books that exceptions should never ever hold a string, because strings themselves can throw exceptions. Any real truth to this?

Basically from my understanding from the scripts is that this was done so all the inhouse Python libraries will have a common error message format (something that is desperately needed) so I can understand why putting the error message string is a good idea. (Almost every method throws exceptions due to the utter need for nothing invalid getting through).

The code in question is the following:

"""
Base Exception, Error
"""
class Error(Exception):
    def __init__(self, message):
        self.message = message

    def __str__(self):
        return "[ERROR] %s\n" % str(self.message)

    def log(self):
        ret = "%s" % str(self.message)
        if(hasattr(self, "reason")):
            return "".join([ret, "\n==> %s" % str(self.reason)])
        return ret

class PCSException(Error):
    def __init__(self, message, reason = None):
        self.message = message
        self.reason = reason
    def __str__(self):
        ret = "[PCS_ERROR] %s\n" % str(self.message)
        if(self.reason != None):
            ret += "[REASON] %s\n" % str(self.reason)
        return ret

This is just the tip of the iceberg, but can someone give me some insight in what makes this a terrible idea? Or if there is a much better exception coding process/style.

Python Solutions


Solution 1 - Python

Robust exception handling (in Python) - a "best practices for Python exceptions" blog post I wrote a while ago. You may find it useful.

Some key points from the blog:

> Never use exceptions for flow-control > > Exceptions exist for exceptional situations: events that are not a > part of normal execution.

Consider 'find' on a string returning -1 if the pattern isn't found, but indexing beyond the end of a string raises an exception. Not finding the string is normal execution.

> Handle exceptions at the level that knows how to handle them > > ... > > The > best place is that piece of code that can handle the exception. For > some exceptions, like programming errors (e.g. IndexError, TypeError, > NameError etc.) exceptions are best left to the programmer / user, > because "handling" them will just hide real bugs.

Always ask "is this the right place to handle this exception?" and be careful with catching all exceptions.

> Document the exceptions thrown by your code > > ... > > thinking about which exceptions your code may throw will help you > write better, safer and more encapsulated code

Solution 2 - Python

> I read several times in books that > exceptions should never ever hold a > string, because strings themselves can > throw exceptions. Any real truth to > this?

What?

Please provide a reference or a link to this. It's totally untrue.

Since all objects can throw exceptions, no object could be contained in an exception by that logic.

No, the "no strings" is simply crazy in a Python context. Perhaps you read it in a C++ context.


Edit

Once upon a time (back in the olden days) you could raise a Python exception by name instead of by the actual class.

raise "SomeNameOfAnExceptionClass"

This is bad. But this is not including a string inside an exception. This is naming the exception with a string instead of the actual class object. In 2.5, this can still work, but gets a deprecation warning.

Perhaps this is what you read "Do not raise an exception with a string name"

Solution 3 - Python

I believe the advice against creating exceptions with a string comes from "Learning Python" (O'Reilly). In a section entitled String Exceptions Are Right Out!, it points out the (now removed) ability to create an exception directly with an arbitrary string.

The code it gives as an example is:

myexc = "My exception string"
try:
    raise myexc
except myexc:
    print ('caught')

This is on p858 of the Fourth Edition (paperback).

Solution 4 - Python

First impression is that it's entirely too much code for an exception.

Formatting exceptions should be done in logger configuration. Same goes for the logging itself.

It also redefines the standard (and deprecated) message attribute, and doesn't call the superclass constructor. (This might or might not break Python 3.0 exception chaining, I haven't tried because I'm running 2.6)

Most of what the extra code does can be realised using BaseException.args, by logging the following as the "message":

'\n==> '.join(exception.args)

I'd argue that if something can be done using a common / idiomatic mechanism, it should especially be done so in exception handling. (Exceptions being a mechanism to signal something across application layers.)

Personally, I try to avoid anything beyond

class SomeException(Exception): pass

(Disclaimer: answer subjective, possibly by nature of the question.)

Solution 5 - Python

class Error(Exception):
    """Base class for other exceptions"""
    pass

class empty_string_error(Error):
    """Raised when the input value is too large"""
    pass
while(1):
    try:
        if("Your Condition"):
            raise empty_string_error
        else:
            print("OUTPUT")
    except empty_string_error:
        print("APT MESSAGE")
        print(" ")
    finally:
        pint("Mandatory code")

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionUberJumperView Question on Stackoverflow
Solution 1 - PythonEli BenderskyView Answer on Stackoverflow
Solution 2 - PythonS.LottView Answer on Stackoverflow
Solution 3 - PythonGraham BorlandView Answer on Stackoverflow
Solution 4 - PythonmillimooseView Answer on Stackoverflow
Solution 5 - PythonAbhishek BakoliaView Answer on Stackoverflow