samedi 7 juillet 2018

Avoiding nested if else statements in Python

It's hard to find answers to this problem when you don't know exactly how to describe it...

What is the most idiomatic way to deal with a fairly deep (but fixed) nested set of tests that you want to run sequentially but terminate as soon as the first one comes up with a successful result?

Instead of the following

Option 1: (results in way too much indentation)

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

Option 2

Another option is to return from the function early but I'm not sure it's good practice to have so many returns scattered about and in this case I would prefer to do one final thing at the end (e.g. print(decision)) before returning:

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 None

Option 3

Finally I could make each test a separate function as described here and call them iteratively, provided each test function has the same set of arguments.

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

This looks the best but I hadn't planned to make a function for every test and some tests can be done with the same function but with different arguments and some are just one-liners whereas others are multiple lines. So then would I have to build a list of functions and arguments before starting the loop? Or make a list of partial functions?

Any better suggestions welcome (before I go ahead with option 3 above)

Aucun commentaire:

Enregistrer un commentaire