osdir.com


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

clever exit of nested loops


vito.detullio at gmail.com wrote:

> Hi
> Today I've added a couple of lines in my source code, and I'm very ashamed
> of it. it "runs", and I know what it does (for now), but it's "too
> clever". I have "abused" the "else" clause of the loops to makes a break
> "broke" more loops
> 
> 
>     for i in range(10):
>         print(f'i: {i}')
>         for j in range(10):
>             print(f'\tj: {j}')
>             for k in range(10):
>                 print(f'\t\tk: {k}')
> 
>                 if condition(i, j, k):
>                     break
> 
>             else:        # if there weren't breaks in the inner loop,
>                 continue # then make anoter outer loop,
>             break        # else break also the outer one
> 
>         else:
>             continue
>         break
> 
> the "magic" is in that repeated block... it's so convoluted to read...
> still it's very useful to omit "signals" variables or the need to refactor
> it in a function with an explicit return or other solutions.
> 
> is there any chance to extends the python grammar to allow something like
> 
> 
>     for i in range(10) and not break:

I think that is much too close to a logical expression. If I were to add a 
way to break out of an inner loop I'd introduce a fullblown (intra-function) 
goto.

So far I'm happy with generators; in my actual use cases something like

    def g():
        for i in range(10):
            print(f'i: {i}')
            for j in range(10):
                print(f'\tj: {j}')
                for k in range(10):
                    print(f'\t\tk: {k}')
                    yield i, j, k

    for i, j, k in g():
        if condition(i, j, k):
            break

looks natural. Another option might be a dedicated exception:

    class Break(Exception):
        pass

    try:
        for i in range(10):
            print(f'i: {i}')
            for j in range(10):
                print(f'\tj: {j}')
                for k in range(10):
                    print(f'\t\tk: {k}')

                    if condition(i, j, k):
                        raise Break
    except Break:
        pass