简体   繁体   中英

What is preferable way to handle exceptions?

If I'm not sure at something while writing some code I'm trying to read The Zen of Python once more. For this time those lines hesitate me.

Errors should never pass silently.
Unless explicitly silenced.

At current code I have some functions which might look like this:

def add_v_1(a, b):
    return a + b 

And all calls for them like:

c = add_v_1(7, [])

Exception for such code will bubble up and caught at upper layers.

But should it be like this?

add_v_1 can raise TypeError exception and I want to recover from it. So, the possible call of function would be:

try:
    c = add_v_1(7, [])
except TypeError:
    print "Incorrect types!"

But for every call, I should do that exception handling. Which looks to heavy.

So, I can do:

def add_v_2(a, b):
    try:
        return a + b
    except TypeError:
        print "Incorrect types!"

and a call would be:

c = add_v_2(7, [])

which looks cleaner.

Seems all of those approaches follow The Zen of Python but which one of them is better choice?

With reference to your example, it's debatable as to whether you should catch the exception inside the function. Doing so will return None from the function, which then burdens the calling code with checking the return value of the function, and treating None as an error. It effectively replaces exception handling with error checking. The former is generally more Pythonic.

You should ask whether it makes sense to catch an error such as attempting to add 2 completely different data types. Doing so in this case would seem to be a programming error, not really the sort of thing that you would expect during normal execution.

And what could you do to handle such an error? There doesn't seem to be any useful value that could be returned within the domain of the function's expected output... other than None to signal that a result could not be produced. But the calling code still has to perform some kind of error checking... so it might as well just handle an exception - at least it only has to handle that once.

But the example is contrived, and it's difficult to give blanket advice. In this particular situation, for the reasons above, I would allow the exception to propagate to the calling code and handle it there.

You should handle the except when you are able to recover from it. If you try to add two values with incompatible type there is nothing you could do to recover from that (without further context).

Lets assume you wrote an IntegerWrapper class and your function "add_v_2" should generally try to concatenate two value.

def add_v_2(a, b):
    try:
        return a + b
    except TypeError as e:
        if isinstance(a, IntegerWrapper):
            return str(a) + b
        else:
            print("I dont know how to handle this type: " + type(a).__name__)
            # reraise the error so the caller can handle it
            raise

This would try to recover from a being of the "wrong type", but if you know how to recover from it. If it doesn't know (a is of another type) it reraises the Exception so someone who know how this can be handled sees the error.

(Of course that implementation contains bugs, it's not meant to be a "good implementation")

Input:

def add_v_2(a, b):
    try:
        return a + b
    except Exception as e:
        print str(e)
c = add_v_2(7, [])
print (c)

Output:

unsupported operand type(s) for +: 'int' and 'list'
None

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM