在 Python 中的异常处理程序中捕获异常的更简洁的方法



在Python程序中,通常使用try-except 块捕获异常:

try:
    # Do stuff
except ValueError:
    # Handle exception

据我所知,在异常处理程序中捕获异常的最佳方法是嵌套的 try-except 块。但是,对于许多嵌套的 try-catch 块,这可能会变得有点混乱:

try:
    # Some assignment that throws an exception if the object is not in the list
    try:
        # Some assignment function that throws an exception if the the object is not already in the database
        # Error Handling
    except ValueError:
        try:
            # Some function that throws an exception if the object does not have an undesired property
            # Error Handling
        except AttributeError:
            try:
                # Some function that throws an exception if an error happens
            except Exception:
                # Exception handling
except ValueError:
    # Exception handling

有没有更整洁的方法可以做到这一点?像这样:

try:
   # Some assignment that throws an exception if the object is not in the list
   try:
       # Some assignment function that throws an exception if the object is not already in the database
   except ValueError:
       # Some function that throws an exception if the object does not have an undesired property
   exceptexcept AttributeError:
       # Some function that throws an exception if an error happens
   exceptexcept Exception:
       # Exception handling 
except ValueError:
   # Exception handling

这听起来像是一个循环,你想继续尝试,直到你成功或用完选择。所以你可以这样实现它,例如,像这样的东西

# Each pair contains a function to call and an exception that can be caught.
# If that exception is raised, the next function will be tried.
action_list = [
    (get_from_list, ValueError),  # throws ValueError if item can't be retrieved
    (get_from_database, ValueError),  # throws ValueError if item can't be retrieved
    (get_from_object, AttributeError),  # throws AttributeError if item lacks desired property
]
result = None
for action, ex in action_list:
    try:
        result = action(key)
        break
    except ex:
        continue

您可以通过让所有帮助程序函数引发自定义异常(如"NotFound"(来整理一下,然后将其用作检查下一级别的信号,如下所示:

# actions to try; all raise NotFound if unsuccessful
action_list = [
    get_from_list, get_from_database, get_from_object
]
result = None
for action in action_list:
    try:
        result = action(key)
        break
    except NotFound:
        continue

或者,您可以将所有步骤放在一个函数中,该函数在成功后立即返回。这样,您的赋值可以在常规代码中完成,而不是使用帮助程序函数:

def get_value(key):
    try:
        return some_list[int(key)]
    except ValueError:
        pass
    try:
        return get_from_database(key)
    except ValueError:
        pass
    try:
        return getattr(some_object, key)
    except AttributeError:
        pass
    return None

如果你不想要另一个函数,你可以滥用for循环:

result = None
for _ in range(1):
    try:
        result = some_list[int(key)]
        break
    except ValueError:
        pass
    try:
        result = get_from_database(key)
        break
    except ValueError:
        pass
    try:
        result = getattr(some_object, key)
        break
    except AttributeError:
        pass

或者,您可以使用带有自定义Found例外的单个外部try/except作为"结构化goto":

result = None
try:
    try:
        result = some_list[int(key)]
        raise Found
    except ValueError:
        pass
    try:
        result = get_from_database(key)
        raise Found
    except ValueError:
        pass
    try:
        result = getattr(some_object, key)
        raise Found
    except AttributeError:
        pass
except Found:
    pass  # all good

或者有这个久经考验但真实的结构:

result = None
if result is None:
    try:
        result = some_list[int(key)]
    except ValueError:
        pass
if result is None:
    try:
        result = get_from_database(key)
    except ValueError:
        pass
if result is None:
    try:
        result = getattr(some_object, key)
    except AttributeError:
        pass

最新更新