Let's say I have these parsers:
parsers = {
".foo": parse_foo,
".bar", parse_bar
}
parse_foo
and parse_bar
are both generators that yield rows one by one. If I wish to create a single dispatch function, I would do this:
def parse(ext):
yield from parsers[ext]()
The yield from syntax allows me to tunnel information easily up and down the generators.
Is there any way to maintain the tunneling while modifying the yield results?
Doing so while breaking the tunneling is easy:
def parse(ext):
for result in parsers[ext]():
# Add the extension to the result
result.ext = ext
yield result
But this way I can't use .send()
or .throw()
all the way to the parser.
The only way I'm thinking of is by doing something ugly like try: ... except Exception: ...
and pass the exceptions up, while doing the same for .send()
. It's ugly, messy and bug-prone.
Unfortunately there is no built-in that does it. You may implement it yourself using classes but a package called cotoolz implements a map()
function that does exactly that.
Their map function is 4 times slower than the builtin map()
but it's aware to the generator protocol, and faster than a similar Python implementation (it's written in C and requires a C99 compiler).
An example from their page:
>>> def my_coroutine():
... yield (yield (yield 1))
>>> from cotoolz import comap
>>> cm = comap(lambda a: a + 1, my_coroutine())
>>> next(cm)
2
>>> cm.send(2)
3
>>> cm.send(3)
4
>>> cm.send(4)
Traceback (most recent call last):
...
StopIteration