简体   繁体   中英

How do I have a python function return an exception traceback, or the result?

Lets say I have a function:

def ReadFile():
    with open("/etc/passwd") as file:
        data = file.read()

This function might succeed, in which case it needs to return a result, or it might fail, in which case I want to return a traceback of the exception, which will get emailed to me so I know something failed in my program, and exactly what failed.

To do this, I can do something like:

import traceback

def ReadFile():
    try:
        with open("/etc/passwd") as file:
            data = file.read()
    except IOError:
        return traceback.format_exc()
    return data

If it is able to read the file successfully, it returns the contents of the file. Otherwise, it returns the traceback of the exception.

traceback.format_exc() returns a string. If ReadFile() is supposed to return a list, or tuple or integer if it succeeds, than things are easy - when you call ReadFile(), if the result returned is a string, you know it failed and you can run code that emails you the error, and if the result is the type you expected (int, tuple, list or w/e), than you know it worked.

If ReadFile() is supposed to return a string, as it does in my example, than figuring out if ReadFile() succeeded or failed becomes significantly more difficult, as you need to parse the string to figure out if it looks like a traceback or the result you expected.

Is there a better way to do this? Perhaps some way to have traceback return some sort of object with the same information as traceback.format_exc() contains, so that it's easier to figure out if ReadFile() succeeded or failed?

I suggest, instead of catching the exception inside this method, let it raise an exception and catch it from wherever you are calling.

In other words, don't put your try catch in that method. Put the try catch around whatever is calling that method, and catch what it could raise instead.

So, have this instead:

import traceback

def ReadFile():
    with open("/etc/passwd") as file:
        data = file.read()
    return data

try:
    r = ReadFile()
except IOError:
    traceback.format_exc()
    # or log or whatever operation

Alternatively, if you really want to keep your exceptions handled in that method and want to return some kind of "fail" signal, then you should probably return the exception object instead and look to see if it exists.

So, you can do this as well. Return the Exception object when you raise and check for it when you call your method to see if there was an exception

def ReadFile():
    try:
        with open("/etc/passwd") as file:
            data = file.read()
    except IOError as exc:
        return exc
    return data

if isinstance(r, Exception):
    # do exception things here

I would opt for the first option, though.

Exceptions already "return" to the enclosing scope, this is entire reason why exceptions exist in the first place.

# See how simple this is?
def read_file():
    with open('/etc/passwd') as file:
        return file.read()

You then handle the exception at an appropriate place in the call chain, but only at the appropriate place. For expected exceptions you want to handle in specific ways, handle them where you have enough information to handle them correctly. For general exceptions, handle them at the top level event loop, or simply propagate them up and have the interpreter print them out.

Like most other things, the exact way you want to handle exceptions will differ from program to program. But returning exceptions as a function result is counterproductive.

If you want to return the exception object you can just do:

def ReadFile():
    try:
        with open("/etc/passwd") as file:
            data = file.read()
    except IOError as ex:
        return ex
    return data

However as Ismail says, its better to let it throw the exception like

def ReadFile():
    with open("/etc/passwd") as file:
        return file.read()

... # Some code that eventually calls the function
...
try:
    data = ReadFile()
except IOError:
    print("File read failed")
    ... # Handle error

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