Hacker News new | ask | show | jobs
by sslnx 2685 days ago
Here is the greatest inconvenience of Python exceptions for me. Say you have to try 10 different methods, and you only need one to work. Then you have to write 10 try...except blocks so that each next block is indented relative to previous. This creates unreadable code and does not scale for say 100 methods. The solution that came to mind is labeling try blocks and referring them in except blocks. For example:

  try as method1:
      method1()
  except@method1 try as method2:
      method2()
  except@method2 try as method3:
      method3()
  except@method3:
      raise NoMethodWorked()
4 comments

I can't think of a single time I've needed a large collection of "backup" methods in case of a chain of failures; I can't even think of an example which could scale to 100. Anyways, this solution does scale:

    methods = [method1, method2, method3, method4]
    for method in methods:
        try:
            method()
        except Exception:
            pass
        else:
            break
    else:
        raise NoMethodWorked()
You can even pair specific exceptions to each method:

    methods = [(method1, TypeError), (method2, KeyError)]
    for m, e in methods:
       try: m()
       except e: ...
But the whole thing really sounds like you're trying to do too much with one function and you really should rethink the whole structure of your code.
This is really helpful. Thank you.
There are several solutions that occured to me off the top of my head, here's the simplest one:

    try:
        method1()
        return
    except Exception: # or a more specific exception type
        pass # try the next method
    try:
        method2()
        return
    except Exception:
        pass
    # ...
    try:
        method10()
    except Exception:
        raise NoMethodWorked()
Seriously, there are so many ways to solve this in a readable, maintainable way, without resorting to introducing weird new syntax.
Who.....codes like this? Use a method dispatch instead, and have the dispatcher worry about throwing the exception:

    try:
        DispatchController.dispatch()
    except:
        raise DispatchFailed()
And/or use a lookup table. Especially since methods, classes, decorators, etc are all first class citizens in Python.
You probably want to look in to try-except-else patterns.