3

i want to be able to raise exception like the built-in ones, you can either pass a message along with it, or just raise the class name(instance created implicitly). like this

raise IndexError

raise IndexError('Something went wrong, bro')

is my following code correct ?

initially i'm thinking about this:

class SomeError(Exception):
    def __init__(self, *args):
        if args:
            print ' '.join(args)

class SomeCriticalError(SomeError):
    def __init__(self, *args):
        super(SomeCriticalError,self).__init__(*args)
        print 'This is a critical error, process stopped ...'
        sys.exit(1)

class SomeCookiesError(SomeCriticalError):
    def __init__(self, *args):
        print 'Firefox cookies retrieving failed ..'   
        super(SomeCookiesError,self).__init__(*args)

but in this case, i have to define __init__() for every subclass of CmiCriticalError, i felt something must be wrong ( calling super() in each subclass seems awkward ), then i tried this

class SomeError(Exception):
    def __init__(self, *args):
        if args:
            print ' '.join(args)
        else:
            print self

class SomeCriticalError(SomeError):
    def __init__(self, *args):
        super(SomeCriticalError,self).__init__(*args)
        print 'This is a critical error, process stopped ...'
        sys.exit(1)

class SomeCookiesError(SomeCriticalError):
    def __str__(self):
        return 'Firefox cookies retrieving failed ..'

but this still feels awkward, what am i missing ?

basically what i want to do is handle exception in the exception instance itself, like the sys.exit() in SomeCriticalError, and because in my main code, i may raise SomeCookiesError at multiple places, i don't want to pass the same message string argument each time, so can i do what the built in exceptions do ? ( when no argument is passed, print default message )

3
  • 1
    pyvideo.org/video/880/stop-writing-classes - food for thought Commented Mar 8, 2014 at 2:59
  • @isedev thanks! already watching it, but in my case, you are saying i should do the print in try/except , and do the sys.exit() in except right ? and avoid using exceptions in this case. but i may need CmiCookiesError in multiple places of my code, say 10 places. so use try/except at these 10 places ? Commented Mar 8, 2014 at 3:11
  • I think the line of though is this: does your exception occur in such a way that it needs to be uniquely distinguishable? if yes, create your own class and handle as appropriate (I would still put the print under except YourException: rather than in YourException); if not, raise a standard exception and handle it where it is not ambiguous. Commented Mar 8, 2014 at 3:15

1 Answer 1

2

Generally an Exception subclass isn't responsible for dealing with the problem that lead to it being raised. That's up to the error handling code (e.g. the try/catch statements that are wrapped around the place where the exception was raised). The exception type should probably limit itself to presenting a nice message, and encapsulating any appropriate data.

So, in your example, you should deal with "critical" errors simply by not catching them (or only catching them at the very top level, before quitting). Many exception classes can be trivial:

class SomeCriticalError(Exception):
    pass

Some other exception classes might do a bit more, but they should be focused on documenting the appropriate details of the situation, rather than how it is resolved:

class CookieError(Exception):
    def __init__(self, cookie_name):
        super(CookiesError, self).__init__("Could not find Firefox cookie {!r}"
                                           .format(cookie_name)) # custom message

If for debugging a CookieError you needed some extra data, you could have your exception class save it to self.data or whatever (though if you want the raise CookieError syntax to work you need to make all the arguments to the __init__ method optional).

Sign up to request clarification or add additional context in comments.

4 Comments

but why? Exception already provides the facility of passing arguments which are stored in <instance of Exception>.args... why not defer strings/messages to the point where the exception is handled, rather than where it is raised? i.e. class CookieError(Exception): pass and retrieving cookie_name as <instance of CookieError>.args[0]
In my example you're probably right, that it doesn't make sense for the exception to do the string formatting. However, if the object you pass to the exception constructor is something heavy-weight (like an object that connects you to a running web browser) it might make sense for the exception to split out the relevant bits of the data into its own attributes (or arguments to super().__init__) rather than saving the heavyweight thing directly. While in that case you could say it's the raising code's job to split up the data, it may make sense for the exception to do some of the work.
@isedev: One potential problem with retrieving things through the args list rather than via attributes names is that it propagates dependencies on the calling sequence of the exception's constructor outside of itself. I think the exception constructor's role is to preprocess and retrieve relevant information about what has occurred and make it accessible in simple consistent manner by exception handlers.
@isedev: Section 8.5. User-defined Exceptions in the Python Tutorial says "Exception classes can be defined which do anything any other class can do, but are usually kept simple, often only offering a number of attributes that allow information about the error to be extracted by handlers for the exception" (emphasis mine) certainly seems to back this approach.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.