[Python-ideas] More alternative names for yield-from

Arnaud Delobelle arnodel at googlemail.com
Fri Feb 20 17:01:50 CET 2009


2009/2/20 Greg Ewing <greg.ewing at canterbury.ac.nz>:
> I still wish I could find a better name for it.

I think 'yield from' is better than all the other suggestions apart
from 'yield *' which would be my choice.

A while ago I created a function to almost exactly add the
functionality you describe in your PEP including the return behaviour,
which I implemented using raise RETURN( ... ).  I've slightly modified
it so it agrees with your specification and include it in this message
after some very simple examples.  Of course it would not help you
implement the PEP but I thought it may be handy to play with some
examples in order to fine tune the PEP.

The function is called 'co' and applied to a generator function it
turns it into a generator that implements the special behavior of
yield FROM ( ... ) raise RETURN ( ... ).  Here are some very simple
examples and the implementation of co() follows at the end.


#
# List flattener.
#

def coflatten(x):
    if isinstance(x, list):
        for y in x:
            yield FROM( coflatten(y) )
    else:
        yield x

flatten = co(coflatten)

>>> list(flatten([[[[1,2,3]]],4,5]))
[1, 2, 3, 4, 5]


#
# Something like Guido's tree example
#

class Tree(object):
    def __init__(self, label, children=()):
        self.label = label
        self.children = children
    @co
    def __iter__(self):
        skip = yield self.label
        if skip:
            yield 'SKIPPED'
        else:
            yield 'ENTER'
            for child in self.children:
                yield FROM( child )
            yield 'LEAVE'

>>> tree = Tree('A', [Tree('B'), Tree('C')])
>>>
>>> list(tree)
['A', 'ENTER', 'B', 'ENTER', 'LEAVE', 'C', 'ENTER', 'LEAVE', 'LEAVE']

>>> i = iter(tree)
>>> skip = None
>>> try:
...     while True:
...         a, skip = i.send(skip), None
...         print a
...         if a == 'B':
...             skip = True
... except StopIteration:
...     pass
...
A
ENTER
B
SKIPPED
C
ENTER
LEAVE
LEAVE


#
# Simple example with raise RETURN ( ... )
#

@co
def gen():
    a = yield FROM( co_nested() )
    yield a

def co_nested():
    yield FROM( [1, 2] )
    raise RETURN( 3 )

>>> list(gen())
[1, 2, 3]


#
# Implementation of co(), FROM, RETURN
#

class FROM(object):
    def __init__(self, gen, val=None):
        self.data = gen, val

class RETURN(StopIteration):
    def __init__(self, val=None):
        self.val = val

def co(cogen, val=None):
    def gen(*args, **kwargs):
        gen = cogen(*args, **kwargs)
        val = None
        callstack = []
        while True:
            try:
                ret = gen.next() if val is None else gen.send(val)
            except StopIteration, e:
                if callstack:
                    gen, val = callstack.pop(), getattr(e, 'val', None)
                    continue
                raise
            if type(ret) is FROM:
                callstack.append(gen)
                gen, val = ret.data
                gen = iter(gen)
            else:
                try:
                    val = yield ret
                except Exception, e:
                    if hasattr(gen, 'throw'):
                        val = yield gen.throw(e)
                    else:
                        raise
    return gen

-- 
Arnaud



More information about the Python-ideas mailing list