Home > Software design >  A Python try/except function to rule them all (with different inputs) is possibile?
A Python try/except function to rule them all (with different inputs) is possibile?

Time:03-08

I'm trying to define in Python a try/except function that can handle various other function. The idea is quite this one:

def func1(x,y):
    z = x y
    return z
    
def error_check(func1):
    try: stuff = func1()
    except: 
        print('Error')     
    return stuff
    
error_check(func1('1',2))

In this case, with those inputs, the error_check function doesn't even work. The aim is that I can use error_check with another func2 with a diverse number of inputs. For examples:

def func2(w,x,y):
    z = w x y
    return z

Is that possible?

Thanks a lot

CodePudding user response:

The core problem with this whole idea is that catching an error doesn't mean you fixed the error. Just try your function with a func1 that raises an exception and you'll see the problem:

>>> def error_check(func1):
...     try:
...         stuff = func1()
...     except:
...         print('Error')
...     return stuff
...
>>> def oops():
...     raise ValueError
...     print("Computing the answer...")
...     return 42
...
>>> error_check(oops)
Error
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in error_check
UnboundLocalError: local variable 'stuff' referenced before assignment

Note that we don't see Computing the answer... in the output, and our function does not return 42! There is nothing we can do in error_check that will change this.

The problem is that if func1 raises an exception, it does not return anything. Hence there is no stuff to return. You can't force a function to "work" by just ignoring the exception it raises; if a function raises an exception, it means it could not do the thing it was supposed to do.

Maybe you're okay with this and want your error_check to return None instead of whatever func1 was supposed to return. If so, you could do:

def error_check(func1):
    try:
        return func1()
    except Exception as e:
        print(f"Error")

This will implicitly return None if there's an exception. It won't raise another exception, but func1 is still not going to do the thing that it was supposed to do:

>>> error_check(oops)
Error
>>>

Note that if we needed that 42 value for something else in our program, that thing is now probably going to raise an error, and if you catch that error, the thing after it will raise an error, and so on, and so on. Ultimately, you don't do yourself any favors by just catching errors and ignoring them.

All that said, if you want to be able to pass other arguments to func1, use *args and **kwargs:

def error_check(func1, *args, **kwargs):
    try:
        return func1(*args, **kwargs)
    except Exception as e:
        print(f"Error: {e}")

Now you can do:

error_check(func1, '1', 2)

and func1 will be called within error_check with *args of ('1', 2).

CodePudding user response:

Your issue is that in the last line there, you are actually calling func1 and then calling error_check on the result. Try something like this instead, where the lambda delays evaluation until the try block like we want:

def func1(x,y):
    z = x y
    return z
    
def error_check(func1):
    try:
        stuff = func1()
        return stuff
    except: 
        print('Error')     
        return None
    
error_check(lambda: func1('1',2))

You also have an error in that stuff is undefined if the try block failed, so I took the liberty of fixing that.

  • Related