Are nested try/except blocks in python a good programming practice?

后端 未结 11 2033
情歌与酒
情歌与酒 2020-12-07 08:33

I\'m writing my own container, which needs to give access to a dictionary inside by attribute calls. The typical use of the container would be like this:

dic         


        
相关标签:
11条回答
  • 2020-12-07 09:19

    In Python it is easier to ask for forgiveness than permission. Don't sweat the nested exception handling.

    (Besides, has* almost always uses exceptions under the cover anyways.)

    0 讨论(0)
  • 2020-12-07 09:20

    A good and simple example for nested try/except could be the following:

    import numpy as np
    
    def divide(x, y):
        try:
            out = x/y
        except:
            try:
                out = np.inf * x / abs(x)
            except:
                out = np.nan
        finally:
            return out
    
    

    Now try various combinations and you will get the correct result:

    divide(15, 3)
    # 5.0
    
    divide(15, 0)
    # inf
    
    divide(-15, 0)
    # -inf
    
    divide(0, 0)
    # nan
    
    

    [of course we have numpy so we don't need to create this function]

    0 讨论(0)
  • 2020-12-07 09:24

    One thing I like to avoid is raising a new exception while handling an old one. It makes the error messages confusing to read.

    For example, in my code, I originally wrote

    try:
        return tuple.__getitem__(self, i)(key)
    except IndexError:
        raise KeyError(key)
    

    And I got this message.

    >>> During handling of above exception, another exception occurred.
    

    What I wanted was this:

    try:
        return tuple.__getitem__(self, i)(key)
    except IndexError:
        pass
    raise KeyError(key)
    

    It doesn't affect how exceptions are handled. In either block of code, a KeyError would have been caught. This is merely an issue of getting style points.

    0 讨论(0)
  • 2020-12-07 09:27

    Just be careful - in this case first finally is touched BUT skipped too.

    def a(z):
        try:
            100/z
        except ZeroDivisionError:
            try:
                print('x')
            finally:
                return 42
        finally:
            return 1
    
    
    In [1]: a(0)
    x
    Out[1]: 1
    
    0 讨论(0)
  • 2020-12-07 09:28

    For your specific example, you don't actually need to nest them. If the expression in the try block succeeds, the function will return, so any code after the whole try/except block will only be run if the first attempt fails. So you can just do:

    def __getattribute__(self, item):
        try:
            return object.__getattribute__(item)
        except AttributeError:
            pass
        # execution only reaches here when try block raised AttributeError
        try:
            return self.dict[item]
        except KeyError:
            print "The object doesn't have such attribute"
    

    Nesting them isn't bad, but I feel like leaving it flat makes the structure more clear: you're sequentially trying a series of things and returning the first one that works.

    Incidentally, you might want to think about whether you really want to use __getattribute__ instead of __getattr__ here. Using __getattr__ will simplify things because you'll know that the normal attribute lookup process has already failed.

    0 讨论(0)
提交回复
热议问题