Exception Handling Practices / Patterns
frank.ruiz at gmail.com
frank.ruiz at gmail.com
Sat Aug 24 19:32:53 EDT 2013
Hi Steven,
Yea this is great. Thanks for the feedback.
On Saturday, August 24, 2013 3:27:45 AM UTC-7, Steven D'Aprano wrote:
> On Fri, 23 Aug 2013 22:25:55 -0700, snarf wrote:
>
>
>
> [...]
>
> > * Seems like exception handing within Classes is largely avoided and is
>
> > typically only used when calling external libraries.
>
>
>
> There is certainly no rule "avoid exceptions inside classes". Methods
>
> often raise exceptions to signal an error, e.g.:
>
>
>
> "My string".index("spam")
>
>
>
>
>
> Less common, methods can raise exceptions as part of their flow control.
>
> The most obvious example is StopIteration, used by iterators and often by
>
> __iter__ or next methods.
>
>
>
>
>
> > * Try/Except type
>
> > statements seem to be used more within modules, main functions, wrapper
>
> > scripts.
>
>
>
> It depends on whose code you are reading. I don't write a lot of classes,
>
> but when I do, I often use try...except inside them.
>
>
>
> If try...except gets used more frequently in module's top level, it is
>
> because the sort of things that you do at the top level often needs
>
> exception handling. For example, you might have a fallback module:
>
>
>
> try:
>
> import this_module
>
> except ImportError:
>
> import that_module as this_module
>
>
>
>
>
> You will very rarely see that inside a class, since you very rarely
>
> import modules inside a class.
>
>
>
>
>
> > * Classes should be coded in a way that exceptions
>
>
>
> I think you forgot to finish the sentence.
>
>
>
>
>
> > * Better to
>
> > never write your own exceptions (unless you absolutely have to).
>
>
>
> That depends.
>
>
>
> On the one hand, nobody wants a million different exception types. On the
>
> other hand, nobody wants just *one* exception type, and no way to
>
> distinguish between different kinds of errors. Somewhere between one and
>
> one million is an appropriate number of exception types.
>
>
>
> The right answer is to be conservative about creating new exceptions, but
>
> don't be scared to create one when you need one.
>
>
>
> But when you do, it is often better to subclass from an appropriate built-
>
> in exception like ValueError or TypeError or similar, than to subclass
>
> from Exception itself.
>
>
>
>
>
> > * Using
>
> > Exception is typically a bad. More specific the better.
>
>
>
> Yes, you should always try to catch the specific exceptions you care
>
> about:
>
>
>
>
>
> # Best
>
> except ValueError, OverflowError, ZeroDivisionError:
>
>
>
>
>
> # Not so good
>
> except Exception:
>
>
>
>
>
> # Worst
>
> except:
>
>
>
>
>
> Don't use the last one, except maybe in the interactive interpreter,
>
> since it will catch *everything*, even exceptions that probably shouldn't
>
> be caught like KeyboardInterrupt.
>
>
>
>
>
> > * Exceptions
>
> > should never fail silently. (Should exceptions always be logged?)
>
>
>
> Certainly not. Exceptions should fail silently if you don't care about
>
> them. For example, when connecting to a website, there are many temporary
>
> errors that can occur. The best way to handle them is to catch the
>
> exception, sleep for a little while, then try again. You need only care
>
> if repeated attempts to connect, with larger and larger sleeps, continue
>
> to fail.
>
>
>
> Of course, you might have a debug mode that logs all of these, but if
>
> your web browser logged every single time a webpage was slow to respond,
>
> you would soon run out of disk space :-)
>
>
>
> *Errors* should never fail silently, unless explicitly silenced. But an
>
> error isn't an error if you don't care about it, and an exception is not
>
> necessarily an error.
>
>
>
> This is an error, because converting a number to uppercase cannot
>
> possibly mean anything:
>
>
>
> mystring = 42
>
> mystring.upper()
>
>
>
>
>
> This is not necessarily an error, since "the list is empty" could be a
>
> legitimate situation:
>
>
>
> mylist = []
>
> first = mylist[0]
>
>
>
> In this case, it may be appropriate to catch the exception, and either
>
> silently swallow it, or do something else.
>
>
>
>
>
> > Best site I have found for exceptions (hopefully this helps someone): *
>
> > http://c2.com/cgi/wiki?ExceptionPatterns
>
>
>
> I haven't read that page for a long time, but as I recall the c2.com
>
> website, a lot of the ideas there are better suited to Java and C/C++
>
> (and occasionally Lisp) rather than Python. But still, a valuable (if
>
> often confusing) resource.
>
>
>
>
>
>
>
> > I'd be interested in hearing others thoughts on this topic with regards
>
> > to best practices for when to use exceptions, and when to avoid using
>
> > exceptions.
>
>
>
> The try part of a try...except is *very* fast to set up. It's about as
>
> fast as a "pass" (do nothing), so it has little overhead.
>
>
>
> On the other hand, actually *catching* an exception is quite heavy. So
>
> code that catches lots and lots of exceptions may be slow. In that case,
>
> it may be faster to "look before you leap" and test ahead of time:
>
>
>
> # this is faster if most lists are not empty
>
> try:
>
> process(mylist[0])
>
> except IndexError:
>
> handle_empty_list()
>
>
>
> # this is faster if many lists are empty
>
> if mylist:
>
> process(mylist[0])
>
> else:
>
> handle_empty_list()
>
>
>
>
>
> Only profiling your data can tell you which you should use.
>
>
>
>
>
> On the other hand, here you should *always* use try...except:
>
>
>
> try:
>
> myfile = open("name")
>
> except IOError:
>
> handle_error()
>
>
>
>
>
> Because this code is wrong:
>
>
>
> if os.path.exists("name"):
>
> myfile = open("name")
>
> else:
>
> handle_error()
>
>
>
>
>
> It's wrong for a couple of reasons:
>
>
>
> - just because the file exists, doesn't mean you can open it;
>
>
>
> - even if the file exists when you call the os.path.exists function,
>
> doesn't mean it will still exist a millisecond later when you try to open
>
> it.
>
>
>
>
>
>
>
> Hope this is helpful,
>
>
>
>
>
>
>
>
>
> --
>
> Steven
More information about the Python-list
mailing list