[Python-Dev] PEP 479: Change StopIteration handling inside generators

Raymond Hettinger raymond.hettinger at gmail.com
Sun Nov 23 02:11:20 CET 2014


> On Nov 22, 2014, at 2:45 PM, Chris Angelico <rosuav at gmail.com> wrote:
> 
> Does your middleware_generator work with just a single element,
> yielding either one output value or none?


I apologize if I didn't make the point clearly.  The middleware example was 
just simple outline of calling next(), doing some processing, and yielding a
result while letting the StopIteration float through from the next() call.

It was meant to show in summary form a pattern for legitimate uses of next() 
inside a generator.   Some of those uses benefit from letting their StopIteration
pass through rather than being caught, returning, and reraising the StopIteration.

The worry is that your proposal intentionally breaks that code which is currently
bug free, clean, fast, stable, and relying on a part of the API that has been
guaranteed and documented from day one.

Since the middleware() example was ineffective in communicating the need,
here are some real-world examples.

Here's one from Fredrick Lundh's ElementTree code in the standard library
(there are several other examples besides this one in his code are well):

    def iterfind(elem, path, namespaces=None):
        # compile selector pattern
        cache_key = (path, None if namespaces is None
                                else tuple(sorted(namespaces.items())))
        if path[-1:] == "/":
            path = path + "*" # implicit all (FIXME: keep this?)
        try:
            selector = _cache[cache_key]
        except KeyError:
            if len(_cache) > 100:
                _cache.clear()
            if path[:1] == "/":
                raise SyntaxError("cannot use absolute path on element")
            next = iter(xpath_tokenizer(path, namespaces)).__next__
            token = next()
            selector = []
            while 1:
                try:
                    selector.append(ops[token[0]](next, token))
                except StopIteration:
                    raise SyntaxError("invalid path")
                try:
                    token = next()
                    if token[0] == "/":
                        token = next()
                except StopIteration:
                    break
            _cache[cache_key] = selector
        # execute selector pattern
        result = [elem]
        context = _SelectorContext(elem)
        for select in selector:
            result = select(context, result)
        return result

And here is an example from the pure python version of one of the itertools:

    def accumulate(iterable, func=operator.add):
        'Return running totals'
        # accumulate([1,2,3,4,5]) --> 1 3 6 10 15
        # accumulate([1,2,3,4,5], operator.mul) --> 1 2 6 24 120
        it = iter(iterable)
        total = next(it)
        yield total
        for element in it:
            total = func(total, element)
            yield total

And here is an example from Django:

    def _generator():
        it = iter(text.split(' '))
        word = next(it)
        yield word
        pos = len(word) - word.rfind('\n') - 1
        for word in it:
            if "\n" in word:
                lines = word.split('\n')
            else:
                lines = (word,)
            pos += len(lines[0]) + 1
            if pos > width:
                yield '\n'
                pos = len(lines[-1])
            else:
                yield ' '
                if len(lines) > 1:
                    pos = len(lines[-1])
            yield word
    return ''.join(_generator())

I could scan for even more examples, but I think you get the gist.
All I'm asking is that you consider that your proposal will do more
harm than good.  It doesn't add any new capability at all.
It just kills some code that currently works.


Raymond
(the author of the generator expressions pep)



-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20141122/56fa9e66/attachment.html>


More information about the Python-Dev mailing list