[Python-ideas] x=(yield from) confusion [was:Yet another alternative name for yield-from] (original) (raw)

Jacob Holm jh at improva.dk
Wed Apr 8 17:04:34 CEST 2009


Jacob Holm wrote:

Even assuming every relevant object implemented the pattern I suggest, it is still not possible to use yield-from to write something like itertools.dropwhile and have it delegate all send and throw calls correctly. To make that possible, you need exactly the same thing that you need for pre-started coroutines: The ability to replace the next() call made by the yield-from expression with something else. Give me that, and you will also have removed the need for a special pattern for coroutines that should be usable with yield-from.

To be clear, I think the best way of handling this is to add a read-only property to generator objects holding the latest value yielded, and let yield-from use that when present instead of calling next(). (This is not a new idea, I am just explaining the consequences as I see them). The property can be cleared when the frame is released, so there should be no issues with that.

With that property, the dropwhile example becomes trivial:

def dropwhile(predicate, iterable): it = iter(iterable) v = next(it) while predicate(v): v = next(it) return yield from it # Starts by yielding the last value checked, which is v.

More interesting (to me) is that the following helpers allow you to call a pre-started generator using yield-from in the 3 special ways I mentioned without needing the generator constructor to take any magic arguments.

def first_yielding(value, iterable): it = iter(iterable) try: s = yield value except GeneratorExit: it.close() except BaseException as e: it.throw(e) # sets the property so yield-from will use that first else: it.send(s) # sets the property so yield-from will use that first return yield from it

def first_sending(value, iterable): it = iter(iterable) it.send(value) # sets the property so yield-from will use that first return yield from it

def first_throwing(exc, iterable): it = iter(iterable) it.throw(exc) # sets the property so yield-from will use that first return yield from it

Yield None (first value yielded by a @coroutine) as first value

yield from example(*args, **kwargs)

Yield 42 as first value

yield from first_yielding(42, example(*args, **kwargs))

Treat the first next() as a send(42)

yield from first_sending(42, example(*args, **kwargs))

Treat the first next() as a throw(ValueError(42))

yield from first_throwing(ValueError(42), example(*args, **kwargs))

So no new syntax needed, and coroutines are easily callable without the constructor needing extra magic arguments. Also, I am sure the property has other unrelated uses. What's not to like?



More information about the Python-ideas mailing list