如何提高嵌套的try-except-else子句中的代码清晰度? [英] How to improve code clarity in nested try-except-else clauses?

查看:95
本文介绍了如何提高嵌套的try-except-else子句中的代码清晰度?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有时候,我可以尝试一堆不同的事情,例如尝试完成一项任务。 G。如果需要获取记录,我可以先尝试查找记录,如果失败,则可以创建丢失的记录,如果失败了,也可以使用磁带。

Sometimes I have a cascade of different things I can try to accomplish a task, e. g. If I need to get a record I can first try to find the record, and if this fails, I can create the missing record, and if this also fails, I can use a tape instead.

失败是通过引发我的代码需要捕获的异常来表示的。

Failing is represented by throwing an exception my code needs to catch.

在Python中,它看起来像这样:

In Python this looks something like this:

try:
  record = find_record()
except NoSuchRecord:
  try:
    record = create_record()
  except CreateFailed:
    record = tape

此已经具有堆积压痕的缺点。如果我有五个选择,那么这段代码看起来会不好看。

This already has the disadvantage of piling-up indentations. If I have five options, this code won't look good.

但是当还有 else try -的c $ c>子句,除了子句除外:

But I find it even more problematic when there are also else clauses to the try-except clauses:

try:
  record = find_record()
except NoSuchRecord:
  try:
    record = create_record()
  except CreateFailed:
    record = tape
    logger.info("Using a tape now")
  else:
    logger.info("Created a new record")
else:
  logger.info("Record found")

find_record()和相应的 Record found 消息距离尽可能远,这使得很难阅读代码。 (仅将 else 子句的代码直接移到 try 子句中是一种选择, except 语句中捕获的异常之一,因此这不是一般解决方案。)

The find_record() and the corresponding Record found message are as far apart as possible which makes it hard to read code. (Moving the code of the else clause directly into the try clause is only an option if this code is definitely not raising one of the exceptions caught in the except statement, so this is no general solution.)

同样,这很丑陋每增加一层嵌套,情况就会变得更糟。

Again, this ugliness gets worse with each added level of nesting.

有没有更好的方法将其放入Python代码

Is there a nicer way to put this into Python code


  1. 不更改行为,

  2. 同时保持 try except <一个主题的/ code>子句紧密结合在一起和/或

  3. 也许还避免了堆积的嵌套和缩进?

  1. without changing the behavior and
  2. while keeping the try and the except clauses of one topic closely together and/or
  3. maybe also avoiding the piling-up nesting and indenting?


推荐答案

您可以使用 for 循环依次尝试变体:

You can use a for loop to successively try variants:

for task, error in ((find_record, NoSuchRecord), (create_record, CreateFailed)):
    try:
        result = task()
    except error:
        continue
    else:
        break
else:
    # for..else is only entered if there was no break
    result = tape

$时输入b
$ b

如果需要 else 子句,可以将其作为单独的函数提供:

If you need an else clause, you can provide it as a separate function:

for task, error, success in (
    (find_record, NoSuchRecord, lambda: logger.info("Record found")),
    (create_record, CreateFailed, lambda: logger.info("Created a new record"))
):
    try:
        result = task()
    except error:
        continue
    else:
        success()
        break
else:
    result = tape
    logger.info("Using a tape now")

请注意,默认情况下 tape not 部分变体-这是因为它没有失败条件。如果应使用变体执行,则可以将其添加为(lambda:磁带,(),lambda:无)

Take note that the default case tape is not part of the variants - this is because it has no failure condition. If it should execute with the variants, it can be added as (lambda: tape, (), lambda: None).

您可以将所有这些放到函数中以供重用:

You can put this all into a function for reuse:

def try_all(*cases):
    for task, error, success in cases:
        try:
            result = task()
        except error:
            continue
        else:
            success()
            return result

try_all(
    (find_record, NoSuchRecord, lambda: logger.info("Record found")),
    (create_record, CreateFailed, lambda: logger.info("Created a new record")),
    (lambda: tape, (), lambda: logger.info("Using a tape now")),
)

如果元组似乎难以阅读,则 NamedTuple 可以用来命名元素。可以将其与普通元组混合使用:

In case the tuples seem difficult to read, a NamedTuple can be used to name the elements. This can be mixed with plain tuples:

from typing import NamedTuple, Callable, Union, Tuple
from functools import partial

class Case(NamedTuple):
    task: Callable
    error: Union[BaseException, Tuple[BaseException, ...]]
    success: Callable


try_all(
    Case(
        task=find_record,
        error=NoSuchRecord,
        success=partial(logger.info, "Record found")),
    (
        create_record, CreateFailed,
        partial(logger.info, "Created a new record")),
    Case(
        task=lambda: tape,
        error=(),
        success=partial(logger.info, "Using a tape now")),
)

这篇关于如何提高嵌套的try-except-else子句中的代码清晰度?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆