These are interesting ideas. It looks like you intend the except clause of the for loop to *only* cover the iter() and next() calls that are implicit in the for loop. You're right that it's awkward to catch exceptions there. However, I worry that when people see this syntax, they will think that the except clause is for handling exceptions in the loop body. (That's certainly what I assumed when I read just your subject line. :-)

On Fri, Jul 26, 2019 at 11:26 AM Serhiy Storchaka <storchaka@gmail.com> wrote:
Python allows you to write code in tight and readable form. Consider the
following example.

     with connect() as stream:  # connect() or __enter__() can fail.
         for data in stream:  # __next__() can fail
             write(data)  # write() can fail

The problem is that different lines can raise an exception of the same
type (for example OSError). We want to catch and handle exceptions
raised when open a connection, when read a data and when write a data in
different ways. Currently you need to expand so convenient Python
statements "with" and "for" (see PEP 343)

     _mgr = connect()
     _enter = type(_mgr).__enter__
     _exit = type(_mgr).__exit__
     _value = _enter(_mgr)
     _exc = True
     try:
         stream = _value
         _it = iter(stream)
         while True:
             try:
                 data = next(_it)
             except StopIteration:
                 break
             write(data)
     except:
         _exc = False
         if not _exit(_mgr, *sys.exc_info()):
             raise
     finally:
         if _exc:
             _exit(_mgr, None, None, None)

and then add "try ... except" around corresponding explicit calls of
`__enter__()` and `next()`.

     try:
         _mgr = connect()
         _enter = type(_mgr).__enter__
         _exit = type(_mgr).__exit__
         _value = _enter(_mgr)
         _exc = True
     except OSError:
         handle_connection_error()
     else:
         try:
             stream = _value
             try:
                 _it = iter(stream)
             except OSError:
                 handle_read_error()
             else:
                 while True:
                     try:
                         data = next(_it)
                     except StopIteration:
                         break
                     except OSError:
                         handle_read_error()
                         break
                     try:
                         write(data)
                     except OSError:
                         handle_write_error()
         except:
             _exc = False
             if not _exit(_mgr, *sys.exc_info()):
                 raise
         finally:
             if _exc:
                 _exit(_mgr, None, None, None)

Does not it look ugly?

I propose to add "except" clause to "for" and "with" statement to catch
exceptions in the code that can't be wrapped with "try ... except".

     for VAR in EXPR:
         BLOCK
     except EXC:
         HANDLER

should be equivalent to

     try:
         _it = iter(EXPR)
     except EXC:
         HANDLER
     else:
         while True:
             try:
                 VAR = next(_it)
             except StopIteration:
                 break
             except EXC:
                 HANDLER
                 break
             BLOCK

and

     with EXPR as VAR:
         BLOCK
     except EXC:
         HANDLER

     try:
         _mgr = EXPR
         _enter = type(_mgr).__enter__
         _exit = type(_mgr).__exit__
         _value = _enter(_mgr)
         _exc = True
     except EXC:
         HANDLER
     else:
         try:
             VAR = _value
             BLOCK
         except:
             _exc = False
             if not _exit(_mgr, *sys.exc_info()):
                 raise
         finally:
             if _exc:
                 _exit(_mgr, None, None, None)

And correspondingly for asynchronous versions "async for" and "async with".

So you will be able to add errors handling like in:

     with connect() as stream:
         for data in stream:
             try:
                 write(data)
             except OSError:
                 handle_write_error()
         except OSError:
             handle_read_error()
     except OSError:
         handle_connection_error()
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-leave@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/M76F3434TXNO2EUMZZ647EABTCNXYGXA/
Code of Conduct: http://python.org/psf/codeofconduct/


--
--Guido van Rossum (python.org/~guido)
Pronouns: he/him/his (why is my pronoun here?)