exceptions == errors?

Skip Montanaro skip at pobox.com
Tue Apr 8 12:34:52 EDT 2003


    Jim> It's always been my impression that exceptions impose considerable
    Jim> performance overhead and therefore should be used to handle only
    Jim> the truly exceptional cases; for any predictable case, one should
    Jim> perform validation and/or error-handling outside the exception
    Jim> mechanism.

Well, yeah, there's a performance hit.  There is, after all, no free
lunch. ;-) The hit is minimal when no exception is raised, and substantially
higher when an exception is raised.  You have to balance the cost against
the clarity of the code.

Here's a trivial example.  If you expect most of the time that an object
will have a particular attribute, it's generally cheaper to just access it
within a try/except statement like so:

    try:
        x += obj.attr
    except AttributeError:
        pass

If, on the other hand, you expect that most of the time the attribute won't
exist, it's generally cheaper to call hasattr():

    if hasattr(obj, "attr"):
        x += obj.attr

Also, this whole thing changes across versions as different features are
added to the Python runtime and different optimizations are made to it.
What's true in 1.5.2 or 1.6 may well not be true in 2.3.  You have to try it
and see.

Here's some timeit output against Python CVS (just cvs up'd today since
Jeremy's and Tim's recent foray into the garbage collector).  The first set
of trials tries both ways to test for the nonexistent attribute
str.__nonzero__:

    >>> t = timeit.Timer(stmt="try:\n  str.__nonzero__\nexcept AttributeError:\n  pass")
    >>> t.timeit()
    17.419214010238647
    >>> u = timeit.Timer(stmt="if hasattr(str, '__nonzero__'):\n  pass")
    >>> u.timeit()
    4.5997350215911865

The next shows access to int.__nonzero__, which does exist:

    >>> t = timeit.Timer(stmt="try:\n  int.__nonzero__\nexcept AttributeError:\n  pass")
    >>> t.timeit()
    1.469681978225708
    >>> u = timeit.Timer(stmt="if hasattr(int, '__nonzero__'):\n  pass")
    >>> u.timeit()
    2.2288650274276733

Skip





More information about the Python-list mailing list