[Python-ideas] "while ... try" - block or "for ... try" - block

Jim Jewett jimjjewett at gmail.com
Wed Jan 11 17:58:40 CET 2012

For me, control flow matching indentation is probably the single most
important feature of python.

What I would support is a more convenient way to inject an exception
handler into an expression.  For example, (a more complicated version
of) your first use case would be improved by a way to say

    (except ConnectError) ==> (time.sleep(timeout); continue)

and your password checker example would be improved by a way to say

    (except WrongPassError) ==> (pass)

More details below.

2012/1/11 Manuel Bärenz <manuel at enigmage.de>:

> while expr try:
>    suite1
> except SomeException:
>    suite2
> else:
>    suite3

Without your explanation, I would still have assumed that the
exception terminated the while.

> while network_is_up() try:
>    connect_to_server()
> except ConnectError:
>    time.sleep(timeout)
> except NoMoreTriesException:
>    print("Couldn't establish connection")
> else:
>    download_stuff()
> finally:
>    make_sure_resource_is_freed()

This would be a lot easier for me to follow with the extra indents.

As best I can tell, under normal circumstances, that will just keep
making new connections, and never get to the download until the
network itself goes down.  Or does the else bind to the try, rather
than the while -- in which case it is still an infinite loop, but at
least succeeds.  I'm also not sure which resource needs to be freed,
so I'll just call it special_resource.  For what I think you wanted, I
can read it a lot easier as:

    with special_resource:
        for keep_trying in range(3):  # not infinity
            if not network_is_up():    # I would prefer this elsewhere ...
            try connect_to_server():
            except ConnectError:
            print("Couldn't establish connection")

which I would in turn prefer to reduce to:

    retry=WaitPolicy('sleep_and_retry', 3)

    with ensure_network(onfail=retry) as network:
        with connect_to_server(transport=network, onfail=retry):

> while receive_packet() try:
>    check_packet()
> except ChecksumError:
>    print("You sent the wrong thing. Try again.")
> except NoMoreTriesException:
>    print("I couldn't get a single useful packet from you :(")
> else:
>    process_packet()
> finally:
>    close_connection()

This time, it looks like only the final packet gets processed.  If
else binds to the try, it makes more sense, but still complains about
not getting a single useful packet even after getting and processing a
dozen.  I would prefer:

    with connection:
        while receive_packet():
            if OK == check_packet():
                print("You sent the wrong thing. Try again.")

or at least (following your API more closely):

    with connection:
        got_any = False
        while receive_packet():
            try check_packet():
                got_any = True
            except ChecksumError:
                print("You sent the wrong thing. Try again.")
        if not got_any:
            print("I couldn't get a single useful packet from you :(")

> A similar thing could be made with "for ... try":
> for password in passwords_i_remember try:
>    connect(password)
> except WrongPassError:
>    pass # No pun intended
> except NoMoreTriesException:
>    print("Not a single one worked.")
> else:
>    check_mailbox()

I honestly don't see that as an improvement over

for password in passwords_i_remember:
    try connect(password):
    except WrongPassError:
        pass # No pun intended
    print("Not a single one worked.")

More information about the Python-ideas mailing list