[Python-ideas] x=(yield from) confusion [was:Yet another alternative name for yield-from]
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?
- Jacob
More information about the Python-ideas
mailing list