On Tue, Nov 3, 2015 at 5:47 PM, Steven D'Aprano <st...@pearwood.info> wrote: > On Fri, 30 Oct 2015 04:43 am, vasudevram wrote: > >> Are there any modern (i.e. for current versions of Python 2 and 3) >> recommended exception handling practices? > > When you say "modern", it sounds like you want to contrast them with "old > fashioned and obsolete" exception-handling practices. I don't know if there > are any obsolete exception-handling practices in Python.
Aside from string exceptions and the "except Type, e:" syntax, I would agree with you. Actually, I can't think of any "obsolete exception-handling practices" in any language. Exception handling is pretty straight-forward: you raise an exception in one place, and you catch it in another. > Bare `except` clauses are very possibly *literally the worst* thing that you > can write in Python: > > https://realpython.com/blog/python/the-most-diabolical-python-antipattern/ I would actually like to disallow the bare except, in the same way that I would disallow the Py2 input() function. In the rare cases where you really do want to catch *every* exception (eg at a boundary between a web server and a request handler, where you would log the exception and return a 500), it should be spelled "except BaseException [as e]:", same as you should use "eval(raw_input())" in those extremely rare cases where you actually want to take keyboard input and evaluate it. But more generally, the over-broad exception handler is a nasty anti-pattern. > (5) Remember that often you can avoid exceptions instead of catching > them. "Look Before You Leap" (LBYL) may be a perfectly good alternative: > > if item in mylist: > idx = mylist.index(item) > process(idx) > else: > result = "not found" > > > but be sensitive to the amount of work done. The above code searches the > list twice instead of just once. Not to mention having race condition possibilities. There are a few places where this is useful, though: start_time = time() work_done = do_some_work() time_spent = time()-start_time or 1 print(f"Did {work_done} jobs in {time_spent} secs: {work_done/time_spent} j/s") The "or 1" is a quick check that means we don't divide by zero. The performance figure becomes meaningless, but if this is a rare case, that's probably fine. > (7) So which is faster, LBYL or catching the exception? That is extremely > sensitive to not just the specific operations being performed, but how > often the exceptional cases occur. In general, you must measure your code > to know. > > But as a very rough rule of thumb, consider looking up a key in a dict: > > if key in mydict: > result = mydict[key] > > versus > > try: > result = mydict[key] > except KeyError: > pass > > > In my experience, catching the KeyError is about ten times more costly than > testing for the key's presence. So if your keys are missing more than one > time in ten, it's probably better to use LBYL. This is actually a tribute to dict performance for key lookup (since that's one of the important operations in a hashtable). It's NOT the case for a list. Exceptions are the "other way" to return something. In a function that always returns a string, returning None is distinguishable (in the same way that a C function can return a NULL pointer); in a function that returns absolutely any object, the only way to signal "no object to return" is to raise an exception. That's why StopIteration exists, for instance. Exceptions are a normal part of program flow - they signal an "exceptional condition" in some small area, but it's normal to cope with exceptional conditions. ChrisA -- https://mail.python.org/mailman/listinfo/python-list