One-Line Exception Handling

30,310

Solution 1

It is not possible to do a one-line exception-handling statement in python. One could write a function to do this.

def safe_execute(default, exception, function, *args):
    try:
        return function(*args)
    except exception:
        return default

Example usage:

from json import loads
safe_execute("Oh no, explosions occurred!", TypeError, loads, None)
# Returns "Oh no, explosions occurred!"
safe_execute("Huh?", TypeError, int, "10")
#Returns 10

Multiple arguments are supported

from operator import div
safe_execute(
    "Divsion by zero is invalid.",
    ZeroDivisionError,
    div, 1, 0
)
# Returns "Divsion by zero is invalid."

safe_execute(
    "Divsion by zero is invalid.",
    ZeroDivisionError,
    div, 1, 1
)
# Returns 1.

The error-catching process may still be interrupted:

from time import sleep
safe_execute(
    "Panic!",
    Exception,
    sleep, 8
)
# Ctrl-c will raise a KeyboardInterrupt

from sys import exit
safe_execute("Failed to exit!", Exception, exit)
# Exits the Python interpreter

If this behavior is undesired, use BaseException:

from time import sleep
safe_execute("interrupted",
             BaseException,
             sleep, 8)
#Pressing Ctrl-c will return "interrupted"
from sys import exit
safe_execute("Naughty little program!",
             BaseException,
             exit)
#Returns "Naughty little program!"

Solution 2

It is possible in one line using exec:

parse_float = lambda x, y=exec("def f(s):\n try:\n  return float(s)\n except:  return None"): f(x)

Solution 3

You can use contextlib to suppress exceptions. If you like to live dangerously you could suppress BaseException, which would suppress all builtin exceptions (probably a bad idea). Or you could pick a safe one relevant to your code, like TypeError.

examples:

from contextlib import suppress

# this will execute right along
with suppress(BaseException): fhasldjkfhsa345315

# even raising an Exception will fly just fine
with suppress(BaseException): raise NameError

# correct code will execute just fine
x=5
with suppress(BaseException): x+=2
print(x) # prints 7

# and in your example:
from json import loads
pleasure = suppress(TypeError) # so each line rolls off the tongue :)

with pleasure: result = loads('{"value": True}')
print(result) # prints {'value': True}

with pleasure: result = loads(None)
print(result) # prints {'value': True} because result never changed
Share:
30,310

Related videos on Youtube

2Cubed
Author by

2Cubed

Python fanatic, night-owl, and lover of beautiful code. "Don't undertake a project unless it is manifestly important and nearly impossible." -Edwin Land

Updated on December 27, 2021

Comments

  • 2Cubed
    2Cubed over 2 years

    In Python, it is possible to use one-liners to set values with special conditions (such as defaults or conditions) in a simple, intuitive way.

    result = 0 or "Does not exist."  # "Does not exist."
    
    result = "Found user!" if user in user_list else "User not found."
    

    Is it possible to write a similar statement that catches exceptions?

    from json import loads
    
    result = loads('{"value": true}') or "Oh no, explosions occurred!"
    # {'value': True}
    
    result = loads(None) or "Oh no, explosions occurred!"
    # "Oh no, explosions occurred!" is desired, but a TypeError is raised.
    
    • TigerhawkT3
      TigerhawkT3 about 8 years
      Why not put the standard try..except into the function?
    • 2Cubed
      2Cubed about 8 years
      @Slayer Interestingly, Python will actually use a string (or any other object, in fact) as an "alternate" for or. 0 or "Does not exist." will return "Does not exist.". (I have tested it.)
    • 2Cubed
      2Cubed about 8 years
      @TigerhawkT3 I do not have access to the internals of the divide_one_by function - assume that it is defined in a separate module which I am using as a dependency.
    • Jongware
      Jongware about 8 years
      @2Cubed: no reason to be surprised. 0 OR x evaluates to x for all values of x, except0 itself.
    • TigerhawkT3
      TigerhawkT3 about 8 years
      So write a wrapper function, perhaps?
    • TigerhawkT3
      TigerhawkT3 about 8 years
      @RadLexus - It evaluates to x when x is 0 as well. It'll simply be 0.
    • Jongware
      Jongware about 8 years
      @TigerhawkT3: does that not evaluate to False instead? (Testing..) Oh I see it indeed does not. :) print 0 or False does, though, proving my point on anything for x. Even 0.
    • 2Cubed
      2Cubed about 8 years
      @TigerhawkT3: Good idea. Thanks!
    • chepner
      chepner about 8 years
      There is a PEP to add something like this, but it hasn't been accepted yet.
    • Alexey Shrub
      Alexey Shrub over 4 years
      suppress maybe useful for some cases stackoverflow.com/a/52020518/8583496
  • thepunitsingh
    thepunitsingh almost 5 years
    You have a great suggestion. I am trying to create a similar workaround for my problem but the code is unable to work. I have detailed the problem at stackoverflow.com/q/56916092/6701627. I will be thankful if you could check the problem and provide some suggestion on it.
  • sp4c38
    sp4c38 almost 3 years
    yeah but that's so horribly unpythonic... it's like putting an image of a website on a website instead of the actual html itself