[Python-Dev] Re: anonymous blocks

Guido van Rossum gvanrossum at gmail.com
Thu Apr 28 02:19:08 CEST 2005

> It's not unlike David Mertz' articles on implementing coroutines and
> multitasking using generators, except that I'm adding more "debugging
> sugar", if you will, by making the tracebacks look normal.  It's just that
> the *how* requires me to pass the traceback into the generator.  At the
> moment, I accomplish that by doing a 3-argument raise inside of
> 'events.resume()', but it would be really nice to be able to get rid of
> 'events.resume()' in a future version of Python.

I'm not familiar with Mertz' articles and frankly I still fear it's
head-explosive material. ;-)

> I think maybe I misspoke.  I mean adding to the traceback *so* that when
> the same error is reraised, the intervening frames are included, rather
> than lost.
> In other words, IIRC, the traceback chain is normally increased by one
> entry for each frame the exception escapes.  However, if you start hiding
> that inside of the exception instance, you'll have to modify it instead of
> just modifying the threadstate.  Does that make sense, or am I missing
> something?

Adding to the traceback chain already in the exception object is
totally kosher, if that's where the traceback is kept.

> My point was mainly that we can err on the side of caller convenience
> rather than callee convenience, if there are fewer implementations.  So,
> e.g. multiple methods aren't a big deal if it makes the 'block'
> implementation simpler, if only generators and a handful of special
> template objects are going need to implement the block API.

Well, the way my translation is currently written, writing next(itr,
arg, exc) is a lot more convenient for the caller than having to write

    # if exc is True, arg is an exception; otherwise arg is a value
    if exc:
        err = getattr(itr, "__error__", None)
        if err is not None:
            VAR1 = err(arg)
            raise arg
        VAR1 = next(itr, arg)

but since this will actually be code generated by the bytecode
compiler, I think callee convenience is more important. And the
ability to default __error__ to raise the exception makes a lot of
sense. And we could wrap all this inside the next() built-in -- even
if the actual object should have separate __next__() and __error__()
methods, the user-facing built-in next() function might take an extra
flag to indicate that the argument is an exception, and to handle it
appropriate (like shown above).

> > > So, I guess I'm thinking you'd have something like tp_block_resume and
> > > tp_block_error type slots, and generators' tp_iter_next would just be the
> > > same as tp_block_resume(None).
> >
> >I hadn't thought much about the C-level slots yet, but this is a
> >reasonable proposal.
> Note that it also doesn't require a 'next()' builtin, or a next vs.
> __next__ distinction, if you don't try to overload iteration and
> templating.  The fact that a generator can be used for templating, doesn't
> have to imply that any iterator should be usable as a template, or that the
> iteration protocol is involved in any way.  You could just have
> __resume__/__error__ matching the tp_block_* slots.
> This also has the benefit of making the delineation between template blocks
> and for loops more concrete.  For example, this:
>      block open("filename") as f:
>          ...
> could be an immediate TypeError (due to the lack of a __resume__) instead
> of biting you later on in the block when you try to do something with f, or
> because the block is repeating for each line of the file, etc.

I'm not convinced of that, especially since all *generators* will
automatically be usable as templates, whether or not they were
intended as such. And why *shouldn't* you be allowed to use a block
for looping, if you like the exit behavior (guaranteeing that the
iterator is exhausted when you leave the block in any way)?

--Guido van Rossum (home page: http://www.python.org/~guido/)

More information about the Python-Dev mailing list