我们说我有这些解析器:
parsers = {
".foo": parse_foo,
".bar", parse_bar
}
parse_foo
和parse_bar
都是逐个生成行的生成器。如果我想创建一个调度函数,我会这样做:
def parse(ext):
yield from parsers[ext]()
语法的收益率使我能够轻松地在生成器中上下传递信息。
在修改收益结果时是否有任何方法可以维持隧道效应? 在破坏隧道时这样做很容易:
def parse(ext):
for result in parsers[ext]():
# Add the extension to the result
result.ext = ext
yield result
但是这样我就无法将.send()
或.throw()
一直用于解析器。
我想到的唯一方法就是做一些像try: ... except Exception: ...
这样丑陋的事情并传递异常,同时为.send()
做同样的事情。它很丑陋,很杂乱,容易出错。
答案 0 :(得分:2)
除try ... yield ... except
之外还有另一种方法:通过实现新的生成器。使用此类,您可以转换基础生成器的所有输入和输出:
identity = lambda x: x
class map_generator:
def __init__(self, generator, outfn = identity,
infn = identity, throwfn = identity):
self.generator = generator
self.outfn = outfn
self.infn = infn
self.throwfn = throwfn
self.first = True
def __iter__(self):
return self
def __next__(self):
return self.send(None)
def _transform(self, value):
if self.first:
self.first = False
return value
else:
return self.infn(value)
def send(self, value):
return self.outfn(self.generator.send(self._transform(value)))
def throw(self, value):
return self.outfn(self.generator.throw(self.throwfn(value)))
def next(self): # for python2 support
return self.__next__()
用法:
def foo():
for i in "123":
print("sent to foo: ", (yield i))
def bar():
dupe = lambda x:2*x
tripe = lambda x:3*x
yield from map_generator(foo(), dupe, tripe)
i = bar()
print("received from bar: ", i.send(None))
print("received from bar: ", i.send("B"))
print("received from bar: ", i.send("C"))
...
received from bar: 11
sent to foo: BBB
received from bar: 22
sent to foo: CCC
received from bar: 33
编辑:您可能希望从collections.Iterator
继承,但在此用例中不是必需的。
答案 1 :(得分:0)
让parse_foo
和parse_bar
添加扩展程序:
def parse_foo(ext):
# Existing code
...
# Add an extension to the item(s)
item.ext = ext
def parse(ext):
yield from parsers[ext](ext)
或者只是在每个函数中对其进行硬编码:
def parse_foo():
# Existing code
...
# Add an extension to the item(s)
item.ext = ".foo"
答案 2 :(得分:0)
不幸的是没有内置功能。您可以使用类自己实现它,但是名为cotoolz的包实现了一个map()
函数,它正是这样做的。
他们的map函数比内置map()
慢4倍,但是它对生成器协议有所了解,并且比类似的Python实现更快(它用C编写并且需要C99编译器)。
他们页面的一个例子:
>>> 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