嵌套 if 子句与级联 return 与断言

Nesting if clauses vs cascade return vs assertion

如果 if 子句中的否定求值会导致 function/method 中的 return 调用,Python 中更推荐的做法是嵌套 if 子句或利用反向求值并调用函数 return?例如:

if required_condition_1:
    if required_condition_2:
        if required_condition 3:
            pass
        return 'error for condition 3'
    return 'error for condition 2'
return 'error for condition 1'

或者:

if not required_condition_1:
    # preparation...
    return 'error for condition 1'

if not required_condition_2:
    # preparation...
    return 'error for condition 2'

if not required_condition_3:
    # preparation...
    return 'error for condition 3'

# if runtime reaches this point it means that it has passed all conditions

假设你要注册一个用户,你需要满足各种条件。用户只有在他们都满意的情况下才会被注册,但错误消息取决于失败的条件。

我的猜测是,在其他情况下,正如用户在答案部分提到的那样,如果特定条件失败,则可能会应用其他操作。然后我想我应该嵌套ifs。但是,我只会 returning 一条错误消息,所以我认为第二种选择更可取。

我也想过断言:

try:
    assert(required_condition_1)
    try:
        assert(required_condition_2)
        # do tasks
    except AssertionError:
        # error for condition 2
except AssertionError:
    # error for condition 1

尽管我认为最后一种方法在处理异常时不太值得推荐。也作为 SO 用户 mentions:

If the code is correct, barring Single-event upsets, hardware failures and such, no assert will ever fail. That is why the behaviour of the program to an end user must not be affected. Especially, an assert cannot fail even under exceptional programmatic conditions. It just doesn't ever happen. If it happens, the programmer should be zapped for it.

我知道这似乎主要基于意见,但对我来说不是,因为所有语言都有产生更具可持续性、可扩展性和可读性的环境,具体取决于其特性和功能。我想知道是否有推荐的方法在方法内部处理这个问题,最重要的是,为什么.

虽然这可以被视为基于意见,但我认为 客观地 第二种方式似乎更具可读性。

在您的第一个示例中,阅读您的代码的人必须解密每个语句与其嵌套的语句在逻辑上不相关,这是您不希望发生的事情。一般来说,嵌套块意味着某种继承逻辑。

第二个例子写的更简洁,不需要太多思考就可以实现逻辑流程。逻辑流程似乎暗示每个条件都应该满足,而不是越陷越深,你想应用的条件越多。

第一种风格有其用例,只是不适用于手头的给定任务:条件检查。


关于你的第二个问题,在此用例中使用断言被认为是不合适的。根据经验,仅当 永远不会出错 但对程序执行非常重要的事情出错时才使用 assert。最明显的用途之一就是写测试用例,一个函数应该给出一定的输出,如果不给你那个输出就很糟糕了。

异常是指您可能会出错的事情例如除以零错误、属性错误等处理用户输入时的错误。

正如 Ziyad Edher 所回答的,第二个更具可读性:

if not required_condition_1:
    # preparation...
    return 'error for condition 1'

if not required_condition_2:
    # preparation...
    return 'error for condition 2'

if not required_condition_3:
    # preparation...
    return 'error for condition 3'

而且,如果您只想拥有 1 个 return,那么:

if not required_condition_1:
    # preparation...
    _error = 'error for condition 1'

elif not required_condition_2:
    # preparation...
    _error = 'error for condition 2'

elif not required_condition_3:
    # preparation...
    _error = 'error for condition 3'

else:
    _error = None

return _error