exception handling in complex Python programs

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Gabriel Genellina

    #16
    Re: exception handling in complex Python programs

    En Wed, 20 Aug 2008 21:49:14 -0300, dbpokorny@gmail .com <dbpokorny@gmai l.comescribió:
    On Aug 20, 10:59 am, Steven D'Aprano <st...@REMOVE-THIS-
    cybersource.com .auwrote:
    >Oh goodie. Another programmer who goes out of his way to make it hard for
    >other programmers, by destroying duck-typing.
    >
    Remember kids: personal attacks are cruise control for cool.
    >
    So this was a simplification - most of the asserts I've written don't
    actually use isinstance, partly because typing isinstance takes too
    long. The point is to create a barricade so that when something goes
    wrong, you get an assertion error against the code you wrote, not an
    exception against doing something like
    >
    print("blah blah %s" % message)
    >
    where message turns out to be None. This is simply a way to make
    debugging a more pleasant experience (quite valuable IMHO since
    debugging is inherently difficult and can be quite aggravating). Here
    is a sampling:
    >
    assert statelt.tag == 'stat'
    assert len(path) 0 and path[0] == '/'
    assert self.__expr != None
    >
    So here asserts are used to made distinctions that are more fine-
    grained than type.
    I think you missed the point. All of those look like program logic verification, and that's fine. But using assert to check user-supplied data is wrong (here "user" may be another programmer if you're developing a library). Assertions may be turned off at runtime.
    If you look at the history of the EAFP concept in Python, then you see
    that it comes from Alex Martelli's Python in a Nutshell around pages
    113-114.
    Mmm, I think it's older than that.
    I don't think the code examples make the case for EAFP very
    well (not that I know what EAFP is in the first place, given that it
    is barely explained.
    Ok, so you don't know what it is, but dislike it anyway?
    I interpret it as "wrap questionable stuff in try/
    except blocks"), and in any case there is practically no support for
    using EAFP as the dominant error-handling paradigm.
    Uh? I think that using try/except IS the "dominant error-handling paradigm" and that's just EAFP.
    Martelli's posts in support of EAFP are heavily skewed towards a
    multithreaded scenario and avoiding race conditions. IMHO, letting
    locking and race condition concerns dictate your error-handling
    paradigm is a case of the tail wagging the dog, especially when there
    are alternatives to this particular tar pit: pipes or a shared nothing
    architecture.
    There are race conditions since multiprogrammin g existed, around '70, and I'm afraid they'll stay for a long time...

    --
    Gabriel Genellina

    Comment

    • Richard Levasseur

      #17
      Re: exception handling in complex Python programs

      One common-place thing I've noticed in a lot of python code is that
      every package or module has a main Error class, and all sub-types
      inherit from that class. So you just catch mylib.Error, and you're
      going to catch all the exceptions that package generates directly.

      There seems to be a lot of concern about what exceptions a functions
      might throw, and what to do when it happens. The way I see it, there
      are only two types of exceptions: those you can recover from, and
      those you can't.

      The only ones -really- worth catching are those you can recover from.
      There's a middle-ground type of 'cleanup', to free any resources, but
      those generally go in a finally block, not an except block.

      For the ones you can't handle, it doesn't matter if you catch them or
      not. If you catch them, what do you do? Log an error message, then
      rethrow it. You're still throwing an exception, so you haven't really
      gained anything. You might repackage it and put additional
      information in the exception so you can do something at a higher
      level. What that is, I don't know. I don't think I've ever passed
      information up in an exception that was of use to the program, and I'm
      hard pressed to think of any information you could provide that could -
      fix- the problem.

      If you can derive recoverable information, then why rethrow? Thats
      pretty much a recoverable situation, so there's not need to rethrow.

      In java, there are checked exceptions, which are nice - they tell you
      what a function might throw, so you know what to catch. I don't think
      this improves the quality of anything, though. It just annoys the
      developer. What they end up doing is writing an application-specific
      exception class, and -everything- gets rethrown as that, and
      everything begins to declare it throws AppError. Whats worse is that
      you have heavily, heavily repackaged exceptions: SQLError -AppError
      -MessageError -AppError -MessageError (yes, i've seen this
      before).

      That is almost completely useless. Sure, you could dig down to
      SQLError, but how do you know to do that? If you knew how far you
      should dig down, that means you know what the problem was, in which
      case, you could have prevented it or aborted early. Whats worse, if
      you have all these re-packaging catch blocks and they just log
      something generic, which becomes common with all the catching going
      on. "Couldn't do foo!", "Bar operation failed!", or "Couldn't fetch
      filters from database" (why? We don't know, its catching an AppError
      instead of something more specific), and then they rethrow the
      exception. While trying to debug something not-during development,
      those messages are completely useless, in fact, they're more than
      useless. They're just more cruft to sift through in a log file.

      Additionally, most root causes of an error are going to originate
      where the input comes from the user. Handling anything at levels
      deeper than that isn't going to gain you much. PrepareQuery threw an
      error because of a missing field? Thats great. Where'd it come
      from? There are 100 calls to PrepareQuery. There's only a few calls
      to ReadUserInput() , and a single informative log message of "Query
      failed, unknown field; fields=a, b, c" is much better than 100 lines
      of traceback smattered with "Unknown field" and "Unable to prepare
      query".

      Finally, they give a false sense of security. "I'm catching
      everything it could throw, so everything will be ok if an exception is
      thrown!" I guess thats true. I guess. The only real advantage is
      the whole program won't crash with the ever-helpful, single line of
      "Segmentati on fault." An improvement, but it doesn't prevent
      anything.

      In a complex system, an error can occur in any function at anytime.
      Adding 'throws' to a method definition doesn't change that.

      I guess my point is: everything Chris Mellon said was spot on.

      Comment

      • eliben

        #18
        Re: exception handling in complex Python programs

        On Aug 19, 7:19 pm, eliben <eli...@gmail.c omwrote:
        Python provides a quite good and feature-complete exception handling
        <snip>

        Thanks for the interesting discussion. Armed by the new information
        and few online sources, I blogged a summary for myself on the topic of
        robust exception handling in Python:



        Comment

        • Bruno Desthuilliers

          #19
          Re: exception handling in complex Python programs

          dbpokorny@gmail .com a écrit :
          On Aug 19, 4:12 pm, Steven D'Aprano <st...@REMOVE-THIS-
          cybersource.com .auwrote:
          >On Tue, 19 Aug 2008 11:07:39 -0700, dbpoko...@gmail .com wrote:
          >> def do_something(fi lename):
          >> if not os.access(filen ame,os.R_OK):
          >> return err(...)
          >> f = open(filename)
          >> ...
          >You're running on a multitasking modern machine, right? What happens when
          >some other process deletes filename, or changes its permissions, in the
          >time after you check for access but before you actually open it?
          >
          This is a good point - if you want to use the correct way of opening
          files, and
          you don't want to worry about tracking down exception types, then we
          can probably
          agree that the following is the simplest, easiest-to-remember way:
          >
          def do_something(fi lename):
          try:
          f = open(filename)
          except:
          <handle exception>
          ...
          Still not correct IMHO - bare except clauses are BAD. You want:

          try:
          f = open(filename)
          except IOError, e:
          <handle exception>

          Opening files is a special case where EAFP is the only correct
          solution (AFAIK). I still liberally sprinkle LBYL-style "assert
          isinstance(...) "
          Which defeats the whole point of dynamic typing...
          and other similar assertions in routines.
          The point
          is that EAFP conflicts with the interest of reporting errors as soon
          as possible (on which much has been written see, for instance Ch. 8 -
          Defensive Programming in Code Complete),
          Defensive programming makes sense in the context of a low-level language
          like C where errors can lead to dramatic results. In high-level
          languages like Python, the worse thing that an unhandled exception can
          cause is an abrupt termination of the process and a nice traceback on
          screen. In this context, defensive programming is mostly a waste of time
          - if you can't *correctly* handle the exception where it happens, then
          doing nothing is the better solution.

          My 2 cents...

          Comment

          • Steven D'Aprano

            #20
            Re: exception handling in complex Python programs

            On Thu, 21 Aug 2008 00:34:21 -0700, eliben wrote:
            On Aug 19, 7:19 pm, eliben <eli...@gmail.c omwrote:
            >Python provides a quite good and feature-complete exception handling
            <snip>
            >
            Thanks for the interesting discussion. Armed by the new information and
            few online sources, I blogged a summary for myself on the topic of
            robust exception handling in Python:
            >
            http://eli.thegreenplace.net/2008/08...tion-handling/
            Just a few random points. You say:

            "Exceptions are better than returning error status codes. Some languages
            (like Python) leave you with no choice as the whole language core and
            standard libraries throw exceptions."

            Of course you have a choice. Your function can return anything you want:

            def mysqrt(x):
            try:
            return math.sqrt(x)
            except ValueError:
            return "Code 37"

            I've written functions that return an object on success and None if the
            function failed. In the context of what I was doing, that made more sense
            than raising an exception.

            Furthermore, the str.find() method returns -1 for not found instead of
            raising an exception. There are probably other examples as well.



            You also wrote:

            "Exceptions exist for exceptional situations: unanticipated events that
            are not a part of normal execution."

            Exceptions can and often are anticipated. E.g. if you write code that
            opens a URL, you better anticipate that the server might reject your
            connection. You better expect to be asked for a cookie, or
            authentication. If you check for robots.txt, you better expect that it
            might not exist. That's all normal execution.

            "When a programmer calls str.find('subst ring') he doesn’t expect an
            exception to be thrown if the substring isn’t found."

            But if he called str.index() then he does expect an exception to be
            thrown, just like for list.index() and dict[key] can raise exceptions.
            They are neither bugs nor unexpected.


            "This is what he called find for. A better approach is to return a
            special value like None or -1."

            Sometimes, maybe. But usually not, because that just complicates the
            calling code. You end up writing code that repeatedly checks that the
            result isn't a special value before doing anything.

            Often a better tactic is to write your code assuming that the result is
            the unexceptional case, and then wrap it in a try...except block to catch
            the exceptional cases.

            "When used for flow-control, exceptions are like goto. There might be a
            few esoteric cases in which they’re appropriate, but 99.99% of the time
            they are not."

            I strongly disagree. try...except is like break or continue. Yes, it
            breaks the linear flow of control, but not in a wild, dangerous way like
            goto.

            It is possible to write bad code with exceptions, but you can write bad
            code with anything.



            --
            Steven

            Comment

            • Bruno Desthuilliers

              #21
              Re: exception handling in complex Python programs

              eliben a écrit :
              On Aug 19, 7:19 pm, eliben <eli...@gmail.c omwrote:
              >Python provides a quite good and feature-complete exception handling
              <snip>
              >
              Thanks for the interesting discussion. Armed by the new information
              and few online sources, I blogged a summary for myself on the topic of
              robust exception handling in Python:
              >

              >
              A couple comments (mostly python-specific, so I post them here):

              """
              When used for flow-control, exceptions are like goto. There might be a
              few esoteric cases in which they’re appropriate, but 99.99% of the time
              they are not.
              """

              Python itself uses exceptions for flow control in iterators.


              """
              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.
              """

              Depends on the context. There are cases where you expect these kind of
              errors - like when dealing with program inputs, inspecting objects etc.
              As a Q&D example:

              while True:
              raw_num = raw_input("ente r a number")
              try:
              num = float(raw_num)
              except TypeError, ValueError:
              print "sorry, '%s' is not a valid number" % raw_num
              else:
              # ok
              break



              """
              This is also the reason why you should be extremely careful with except:
              clauses that catch everything. These will not only catch the exceptions
              you intended, but all of them.
              """

              And remember that SysExit and KeyboardInterru pt *are* exceptions too...

              """
              Document the exceptions thrown by your code
              """

              If you mean "the exceptions *explicitely raised* by your code", then I
              agree. But with any generic enough code, documenting any possible
              exception that could be raised by lower layers, objects passed in as
              arguments etc is just plain impossible. Like, if you have a function
              that takes a file-like object as arg, you just cannot know in advance
              what exceptions this object might raise.

              My 2 cents.

              Comment

              • eliben

                #22
                Re: exception handling in complex Python programs

                http://eli.thegreenplace.net/2008/08...tion-handling/
                >
                Just a few random points. You say:
                >
                "Exceptions are better than returning error status codes. Some languages
                (like Python) leave you with no choice as the whole language core and
                standard libraries throw exceptions."
                >
                Of course you have a choice. Your function can return anything you want:
                >
                Of course. I didn't mean that the language prohibits returning error
                codes, just that you can't use it without employing exception
                handling. I've fixed the wording to make it clearer.
                You also wrote:
                >
                "Exceptions exist for exceptional situations: unanticipated events that
                are not a part of normal execution."
                >
                Exceptions can and often are anticipated. E.g. if you write code that
                opens a URL, you better anticipate that the server might reject your
                connection. You better expect to be asked for a cookie, or
                authentication. If you check for robots.txt, you better expect that it
                might not exist. That's all normal execution.
                This is a point I'm not 100% in accord with. I still think that
                exceptions are for exceptional situations. I've removed the word
                "unanticipa ted" though, because it probably has no place in that
                sentence. However, I think that if one of your valid execution paths
                is w/o robots.txt, you should not use an exception to check whether
                it's there. This indeed uses the "bad side" of exceptions, splitting
                the exetution to two paths.
                Check if robots.txt is there. If it is, open it. If you can't open it,
                *that* is an exception, but if it's just not there, well it's part of
                your application logic. I believe this isn't against EAFP.
                I'm not sure I'm making the distinction clear here, it's a fine point.
                >
                "When a programmer calls str.find('subst ring') he doesn’t expect an
                exception to be thrown if the substring isn’t found."
                >
                But if he called str.index() then he does expect an exception to be
                thrown, just like for list.index() and dict[key] can raise exceptions.
                They are neither bugs nor unexpected.
                >
                But why are there two versions that are the same except for the
                behavior in case it wasn't found ? My wishful imagination is precisely
                because of the reasons I've named. If you *know* it's there,
                use .index() - then, if it fails, it's an exception, but if a part of
                your logic is finding an item that might be missing, use a special
                value because you want to keep the logic in a single path.
                "When used for flow-control, exceptions are like goto. There might be a
                few esoteric cases in which they’re appropriate, but 99.99% of the time
                they are not."
                >
                I strongly disagree. try...except is like break or continue. Yes, it
                breaks the linear flow of control, but not in a wild, dangerous way like
                goto.
                >
                try...except can 'exit' to several 'catch points', unlike break/
                continue. Furthermore, try...except can bring execution to another
                hierarchy level if it's not caught where it's thrown, so it's much
                more like goto in these senses. To find where the execution may go
                you'll find yourself searhching for the exception name over your
                source files, looking for the exception class name in some "except"
                clause. Sounds like looking for a goto label.

                P.S. Thanks a lot for taking the time to comment
                Eli



                Comment

                • eliben

                  #23
                  Re: exception handling in complex Python programs

                  On Aug 21, 12:40 pm, Bruno Desthuilliers <bruno.
                  42.desthuilli.. .@websiteburo.i nvalidwrote:
                  eliben a écrit :On Aug 19, 7:19 pm, eliben <eli...@gmail.c omwrote:
                  Python provides a quite good and feature-complete exception handling
                  <snip>
                  >
                  Thanks for the interesting discussion. Armed by the new information
                  and few online sources, I blogged a summary for myself on the topic of
                  robust exception handling in Python:
                  >>
                  A couple comments (mostly python-specific, so I post them here):
                  >
                  Thanks for the feedback. My comments below:
                  """
                  When used for flow-control, exceptions are like goto. There might be a
                  few esoteric cases in which they’re appropriate, but 99.99% of the time
                  they are not.
                  """
                  >
                  Python itself uses exceptions for flow control in iterators.
                  >
                  Yep, I'm aware of StopIteration, but I'm not sure whether it's a good
                  or a bad feature. I'm a bit wary of the programming style it might
                  encourage in inexperienced programmers. When this behavior is hidden
                  inside the implementation of 'for', fair enough. But when you have to
                  catch exceptions just to walk over some iterable explicitly, I'm not
                  sure the designers of this Python feature made the correct choices
                  here.
                  """
                  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.
                  """
                  >
                  Depends on the context. There are cases where you expect these kind of
                  errors - like when dealing with program inputs, inspecting objects etc.
                  As a Q&D example:
                  >
                  while True:
                       raw_num = raw_input("ente r a number")
                       try:
                           num = float(raw_num)
                       except TypeError, ValueError:
                           print "sorry, '%s' is not a valid number" % raw_num
                       else:
                           # ok
                           break
                  >
                  I agree.
                  """
                  This is also the reason why you should be extremely careful with except:
                  clauses that catch everything. These will not only catch the exceptions
                  you intended, but all of them.
                  """
                  >
                  And remember that SysExit and KeyboardInterru pt *are* exceptions too...
                  >
                  """
                  Document the exceptions thrown by your code
                  """
                  >
                  If you mean "the exceptions *explicitely raised* by your code", then I
                  agree. But with any generic enough code, documenting any possible
                  exception that could be raised by lower layers, objects passed in as
                  arguments etc is just plain impossible. Like, if you have a function
                  that takes a file-like object as arg, you just cannot know in advance
                  what exceptions this object might raise.
                  >
                  This is one of the main concerns with which I started this c.l.py
                  thread ! I think it's a pity that we have no way of anticipating and
                  constraining the exceptions thrown by our code, and that we should
                  strive to make it more explicit. The "function accepting a file" is a
                  case in point. You know what you do with this file, so why can't you
                  know what exceptions might be thrown ? If you're trying to open it,
                  IOError (and OSError ?), etc. Besides, as I noted in the article,
                  perhaps you want to hide some of inner-level exceptions in your own,
                  to keep encapsulation.

                  Eli



                  Comment

                  • Bruno Desthuilliers

                    #24
                    Re: exception handling in complex Python programs

                    eliben a écrit :
                    On Aug 21, 12:40 pm, Bruno Desthuilliers <bruno.
                    42.desthuilli.. .@websiteburo.i nvalidwrote:
                    >eliben a écrit :On Aug 19, 7:19 pm, eliben <eli...@gmail.c omwrote:
                    (snip)
                    >>"""
                    >>Document the exceptions thrown by your code
                    >>"""
                    >>
                    >If you mean "the exceptions *explicitely raised* by your code", then I
                    >agree. But with any generic enough code, documenting any possible
                    >exception that could be raised by lower layers, objects passed in as
                    >arguments etc is just plain impossible. Like, if you have a function
                    >that takes a file-like object as arg, you just cannot know in advance
                    >what exceptions this object might raise.
                    >>
                    >
                    This is one of the main concerns with which I started this c.l.py
                    thread ! I think it's a pity that we have no way of anticipating and
                    constraining the exceptions thrown by our code,
                    Java's "checked exception" system has proven to be a total disaster.
                    and that we should
                    strive to make it more explicit. The "function accepting a file" is a
                    case in point. You know what you do with this file, so why can't you
                    know what exceptions might be thrown ?
                    Reread more carefully. I wrote "a *file-like* object", not "a file".
                    This is the whole point of duck typing. Given that any file-like object
                    will work ok with my function, I have *no way* to know what exceptions
                    this object may raise.
                    If you're trying to open it,
                    Trying to open a file *object* ? heck, it's supposed to be already
                    opened at this stage. And yes, it's a pretty common pattern in Python
                    (which is why I choose this example).

                    Comment

                    • magloca

                      #25
                      Re: exception handling in complex Python programs

                      Bruno Desthuilliers @ Thursday 21 August 2008 17:31:
                      >>If you mean "the exceptions *explicitely raised* by your code", then
                      >>I agree. But with any generic enough code, documenting any possible
                      >>exception that could be raised by lower layers, objects passed in as
                      >>arguments etc is just plain impossible. Like, if you have a function
                      >>that takes a file-like object as arg, you just cannot know in
                      >>advance what exceptions this object might raise.
                      >>>
                      >>
                      >This is one of the main concerns with which I started this c.l.py
                      >thread ! I think it's a pity that we have no way of anticipating and
                      >constraining the exceptions thrown by our code,
                      >
                      Java's "checked exception" system has proven to be a total disaster.
                      Could you elaborate on that? I'm not disagreeing with you (or agreeing,
                      for that matter); I'd just really like to know what you mean by
                      a "total disaster."

                      m.

                      Comment

                      • dbpokorny@gmail.com

                        #26
                        Re: exception handling in complex Python programs

                        On Aug 20, 10:13 pm, Steven D'Aprano <st...@REMOVE-THIS-
                        cybersource.com .auwrote:
                        It might not be enjoyable to have a sarcastic remark directed your way,
                        but it isn't a personal attack. Just because a comment is about something
                        you do doesn't make it a personal attack. Personal attacks are about who
                        you are rather than what you do.
                        If you type in "Personal Attack" in Wikipedia (not an authoritative
                        source, I know) it takes you to the page on ad hominem arguments.
                        There you can find the following example of the fallacious ad hominem
                        argument:

                        Person A makes claim X
                        There is something objectionable about Person A
                        Therefore claim X is false

                        It is, ultimately, a matter of opinion, but "going out of one's way to
                        make it hard for other programmers" sounds objectionable to me. I
                        mean, I wouldn't want to work with anyone like that!
                        There's an apparent contradiction in your argument. You seem to be
                        arguing against EAFP and in favour of LBYL, but now you're suggesting
                        that you don't use type-checking. As near as I can tell, you don't do
                        type-checking, you don't do duck typing, you don't like catching
                        exceptions. So what do you actually do to deal with invalid data?
                        Here is an example from a Django web app: when there is a bug, a
                        generic Exception is thrown and Django catches it and reports a
                        beautifully formatted stack trace. When something must be reported to
                        the user, a MyAppException is thrown (not the real name). The HTTP
                        request handler for the application is wrapped in a single try:...
                        except MyAppException: .... the big idea is that there should be a
                        maximum of two try/except blocks on the stack at any particular point
                        in time [1]: at a high level (already mentioned) and for wrapping
                        primitive "execute" operations against Rpy and MySQLdb. In practice,
                        this doesn't always happen - there is one place where an EAFP-style
                        construct is used (the "operation" in this case is to generate some
                        HTML and cache it based on some source XML, but the source may have
                        "syntax errors", so if the HTML can't be generated, then cleanup is
                        performed and an error message returned).

                        So to summarize:
                        try/except blocks at boundaries between system components: good
                        try/except blocks within a single component: slightly concerning

                        I think I may have overstated the case against EAFP. There are
                        certainly cases where EAFP makes a lot of sense; I would object to
                        portraying EAFP as an alternative to defensive programming. [Side
                        note: defensive programming serves much the same purpose in Python as
                        it does in C, but I agree that in C there is extra motivation such as
                        avoiding buffer overruns. I think of defensive programming simply as
                        "taking proactive steps to reduce the expected time to debug a program
                        if a programming error should arise".]
                        By the way, if you're worried that isinstance() is too long to type, you
                        can do this:
                        >
                        isin = isinstance
                        isin(123, int)
                        Actually I'm holding out for type objects to grow __lt__ and __le__
                        methods so you can do something like

                        from abstract_base_c lasses import sequence
                        if type(my_obj) <= sequence:
                        ...

                        This is borrowed from the <= notation for subgroups in math (there are
                        probably other cases too). I don't use abstract base classes, so I
                        don't even know if this is right, but hopefully you get the idea.
                        No no no, exceptions are not necessarily bugs!!! A bug is an exceptional
                        circumstance, but not all exceptional circumstances are bugs.
                        I tend to agree, but I have found that thinking about these issues
                        makes me question the wisdom of Python's built-ins throwing exceptions
                        in non-exceptional circumstances (for instance you try to open a file
                        that doesn't exist - IMHO this is about as exceptional as trying a no-
                        wait acquire on a busy lock, in other words it isn't exceptional at
                        all). As long as we are in fantasy realm, one could argue that open()
                        should return a pair like this:

                        f, open_ok = open(...)

                        where open_ok is a status object whose __nonzero__ (in 3.0 __bool__ is
                        used) is true on success and false on an error, and also has an error
                        code and error message field. The idea is from Django's get_or_create
                        method in the db API.

                        [1] That I have to think about. I don't particularly care about try/
                        except blocks in Django's, Rpy's, or MySQLdb's activation records.

                        David

                        Comment

                        • eliben

                          #27
                          Re: exception handling in complex Python programs

                          Here is an example from a Django web app: when there is a bug, a
                          generic Exception is thrown and Django catches it and reports a
                          beautifully formatted stack trace. When something must be reported to
                          the user, a MyAppException is thrown (not the real name). The HTTP
                          request handler for the application is wrapped in a single try:...
                          except MyAppException: .... the big idea is that there should be a
                          maximum of two try/except blocks on the stack at any particular point
                          in time [1]: at a high level (already mentioned) and for wrapping
                          primitive "execute" operations against Rpy and MySQLdb.
                          This actually makes lots of sense as is exactly what Ned Batchelder
                          wrote here:


                          * A-layer generates exceptions,
                          * B-layer can often ignore the whole issue, and
                          * C-layer decides what to do

                          It's worth a read.

                          Comment

                          • eliben

                            #28
                            Re: exception handling in complex Python programs

                            On Aug 19, 7:34 pm, "Chris Mellon" <arka...@gmail. comwrote:
                            On Tue, Aug 19, 2008 at 12:19 PM, eliben <eli...@gmail.c omwrote:
                            Python provides a quite good and feature-complete exception handling
                            mechanism for its programmers. This is good. But exceptions, like any
                            complex construct, are difficult to use correctly, especially as
                            programs get large.
                            >
                            Most of the issues of exceptions are not specific to Python, but I
                            sometimes feel that Python makes them more acute because of the free-n-
                            easy manner in which it employs exceptions for its own uses and allows
                            users to do the same.
                            >
                            Lots of people seem to have this fear. They treat exceptions like they
                            would treat error codes, trying to handle any possible case around any
                            particular call.
                            >
                            This is the wrong thing to do, and it only leads to more fragile code.
                            There are only 2 reasonable things to do with an exception:
                            1) handle it, by which I mean catch the exception knowing what error
                            condition it signifies, and take an appropriate action to correct the
                            error and
                            2) pass it up so something else has a chance at it.
                            >
                            But by 'handling', do you also mean "rethrow with better
                            information" ?

                            I feel there's an inherent clash between two 'good practices' in
                            exception handling:
                            1) Using EAFP over LBYL
                            2) Hiding implementation details

                            Consider this code, which I wrote just yesterday:

                            elif type in ('LinearStartAd dr', 'SegmentStartAd dr'):
                            if len(data) != 4:
                            line_error('exp ecting a 4-byte data field for this record type,
                            got %s' % len(data))
                            self.data.start _address = unpack('>L', data)

                            This is part of a method in a class that parses a data file. I've
                            ended up using LBYL here, to hide an implementation detail. I could've
                            let the Exception from unpack propagate, but that doesn't make much
                            sense with "hiding implementation" . So I'm throwing a more useful
                            exception myself.
                            Was wrapping the call to unpack with try/except that throws my
                            exception a better idea, in your opinion ? Because that makes the code
                            somewhat more convoluted.

                            Eli


                            Comment

                            • magloca

                              #29
                              Re: exception handling in complex Python programs

                              Bruno Desthuilliers @ Thursday 21 August 2008 22:54:
                              magloca a écrit :
                              >Bruno Desthuilliers @ Thursday 21 August 2008 17:31:
                              >>
                              >>>>If you mean "the exceptions *explicitely raised* by your code",
                              >>>>then I agree. But with any generic enough code, documenting any
                              >>>>possible exception that could be raised by lower layers, objects
                              >>>>passed in as arguments etc is just plain impossible. Like, if you
                              >>>>have a function that takes a file-like object as arg, you just
                              >>>>cannot know in advance what exceptions this object might raise.
                              >>>>>
                              >>>This is one of the main concerns with which I started this c.l.py
                              >>>thread ! I think it's a pity that we have no way of anticipating
                              >>>and constraining the exceptions thrown by our code,
                              >>Java's "checked exception" system has proven to be a total disaster.
                              >>
                              >Could you elaborate on that? I'm not disagreeing with you (or
                              >agreeing, for that matter); I'd just really like to know what you
                              >mean by a "total disaster."
                              >
                              One of the most (in)famous Java coding pattern is the empty catchall
                              clause. Read Chris Mellon and Richard Levasseur posts in this thread
                              for more details - they already covered the whole point.
                              Thanks, I missed those. Having read them, I *am* agreeing with you.
                              Personally, I also dislike the predominance in the Java world of only
                              giving type information -- IllegalValueExc eption,
                              ObjectRetrieval FailureExceptio n, and whatever. What was the illegal
                              value? What object couldn't be retrieved? How hard is it to use the
                              with-error-message version of the Exception constructor, and include
                              something that might actually be helpful in debugging?

                              m.

                              Comment

                              • Maric Michaud

                                #30
                                Re: exception handling in complex Python programs

                                Le Thursday 21 August 2008 09:34:47 Bruno Desthuilliers, vous avez écrit :
                                The point
                                is that EAFP conflicts with the interest of reporting errors as soon
                                as possible (on which much has been written see, for instance Ch. 8 -
                                Defensive Programming in Code Complete),
                                >
                                Defensive programming makes sense in the context of a low-level language
                                   like C where errors can lead to dramatic results. In high-level
                                languages like Python, the worse thing that an unhandled exception can
                                cause is an abrupt termination of the process and a nice traceback on
                                screen.
                                ... and leave your datas in inconsistent state. So, what C or any other
                                language could do worse to your application ?
                                In this context, defensive programming is mostly a waste of time
                                - if you can't *correctly* handle the exception where it happens, then
                                doing nothing is the better solution.
                                If I don't buy the argument I actually agree with the conclusion. Each
                                component of a program should try to manage only errors tied to their own
                                logic and let pass others up to the gui logic for rendering errors the good
                                way, persistence logic to rollback unwanted changes, and application logic to
                                continue execution the right way. This is hard to do in C because you have no
                                way to trap an error which happen randomly in the program, ie. a segfault
                                will interrupt the execution anyway.

                                --
                                _____________

                                Maric Michaud

                                Comment

                                Working...