Избегайте вложенной лестницы инструкции else в Python

Bill спросил: 13 июня 2018 в 08:01 в: python

Трудно найти ответы на эту проблему, когда вы точно не знаете, как ее описать ...

Что такое самый идиоматический способ справиться с довольно глубоким (но фиксированным) вложенным набором тестов, который вы хотите запускать последовательно, но прекратить, как только первый из них придет с успешным результатом?

Вместо следующих

Вариант 1: (приводит к слишком большому отступу)

def make_decision():    results = ... some code or function that returns a list or None
    if results:
        decision = random.choice(results)
    else:
        results = ... other code or function
        if results:
            decision = random.choice(results)
        else:
            results = ... other code or function
            if results:
                decision = random.choice(results)
            else:
                results = ... other code or function
                if results:
                    decision = random.choice(results)      ...etc.                                else:
                                    decision = None    print(decision)    return decision

Вариант 2

Еще одна возможность - вернуться из функции раньше, но я не уверен, что хорошая практика состоит в том, чтобы так много возвратов рассеялось, и в этом случае я предпочел бы сделать одну последнюю вещь в конце (например, print(decision)) перед возвратом:

def make_decision():    results = ... some code or function that returns a list or None
    if results:
        return random.choice(results)    results = ... other code or function
    if results:
        return random.choice(results)    results = ... other code or function
    if results:
        return random.choice(results)    ...etc.    else:
        decision = None    return decision

Вариант 3

Наконец, я могу сделать каждый тест отдельной функцией , как описано здесь , и называть их итеративно, если каждая тестовая функция имеет тот же набор аргументов.

def test1(args):
    ...def test2(args):
    ...def test3(args):
    ...def make_decision():    decision = None
    for test in [test1, test2, test3, ...]:
        results = test(args)
        if results:
            decision = random.choice(results)
            break    print(decision)    return decision

Это выглядит лучше, но у меня не было планируется сделать для каждого теста, а некоторые тесты могут выполняться с одной и той же функцией, но с разными аргументами, а некоторые - только с одним слоем, тогда как другие - несколькими строками. Итак, тогда мне нужно будет создать список функций и аргументов перед запуском цикла? Или создать список функций partial?

Любые лучшие предложения приветствуются (прежде чем я продолжу опцию 3 выше)


2 ответа

John Kennedy ответил: 13 июня 2018 в 08:32

Вы можете выбрать любой из вариантов, все зависит от ваших предпочтений. В Варианте 2 я не думаю, что это плохая идея иметь много return, так как они заключены в условный код. Они будут выполняться только в том случае, если это условие True.

В варианте 1 вы можете перейти к elif results:, а не:

if results:
        # some code
    else:
        if results:
               # some code

В вашем коде почти похоже, что вы проверяете тот же results, который выглядит как только один блок if. Вы должны проверять некоторое значение, например. if results == something.

Наконец, вариант 3 выглядит более чистым. И чтобы обернуть, выберите тот, с которым вы чувствуете себя наиболее комфортно.

Bill ответил: 13 июня 2018 в 08:21
Благодарю. elif был бы идеальным, но мне нужно сначала собрать результаты каждого теста перед тестированием (results - список хороших ходов или пустой список). Есть ли способ сделать это в состоянии elif?
John Kennedy ответил: 13 июня 2018 в 08:43
В этом случае вы должны выбрать между вариантами 2 и 3.
Bill ответил: 13 июня 2018 в 08:44
См. Ответ, который я только что придумал.
John Kennedy ответил: 13 июня 2018 в 08:46
Где вы ответили?
Bill ответил: 13 июня 2018 в 08:47
Это должно быть показано выше
Есть решение
Bill ответил: 13 июня 2018 в 08:39

Извините, теперь это очевидно, что переосмыслить его:

def make_decision():    results = ... some code or function that returns a list or None    if results is None:
        results = ... other code or function    if results is None:
        results = ... other code or function    ...etc.    if results is None:
        decision = None
    else:
        decision = random.choice(results)
    print(decision)    return decision
John Kennedy ответил: 13 июня 2018 в 08:49
Как это отличается?
Bill ответил: 13 июня 2018 в 08:55
Извините, Джон, я не думаю, что понимаю ваш ответ. Я думал, что вы предлагаете elif. Я не думаю, что elif работает. Или, пожалуйста, укажите свой предложенный код в своем ответе. Если это то же самое, я удалю этот ответ.
John Kennedy ответил: 13 июня 2018 в 09:34
Я предлагаю вам пойти с 2 или 3.
Bill ответил: 15 июня 2018 в 09:03
Я пошел с моим ответом выше по причинам, изложенным в комментариях выше. Он выглядит чище и делает работу ...