Bre*_*els 16 python generator coroutine tee python-itertools
我有一个对象的树形结构.我需要遍历叶子中的所有项目("值").为此,我目前正在使用如下所示的生成器方法:
class Node(object):
def __init__(self):
self.items = [Leaf(1), Leaf(2), Leaf(3)]
def values(self):
for item in self.items:
for value in item.values():
yield value
class Leaf(object):
def __init__(self, value):
self.value = value
def values(self):
for i in range(2):
yield self.value
n = Node()
for value in n.values():
print(value)
Run Code Online (Sandbox Code Playgroud)
这打印:
1
1
2
2
3
3
Run Code Online (Sandbox Code Playgroud)
现在,a返回的值Leaf将取决于外部参数.我正在考虑使用协程能够将此参数传递给叶节点:
import itertools
class Node2(object):
def __init__(self):
self.items = [Leaf2(1), Leaf2(2), Leaf2(3)]
def values(self):
parameter = yield
for item in self.items:
item_values = item.values()
next(item_values) # advance to first yield
try:
while True:
parameter = (yield item_values.send(parameter))
except StopIteration:
pass
class Leaf2(object):
def __init__(self, value):
self.value = value
def values(self):
parameter = yield
try:
for i in range(2):
parameter = (yield '{}{}'.format(self.value, parameter))
except StopIteration:
pass
n2 = Node2()
values2 = n2.values()
next(values2) # advance to first yield
try:
for i in itertools.count(ord('A')):
print(values2.send(chr(i)))
except StopIteration:
pass
Run Code Online (Sandbox Code Playgroud)
这段代码很不错,但它很有效.它打印:
1A
1B
2C
2D
3E
3F
Run Code Online (Sandbox Code Playgroud)
但是这个解决方案存在问题.我正在广泛地使用itertools.tee(和chain)来轻松保存迭代器的状态,以防我需要回溯.我希望这些也适用于协同程序,但唉,没有这样的运气.
我正在考虑的一些替代解决方案:
第一种选择似乎最具吸引力.但也许有更好的选择?
一些上下文:我在RinohType中使用此构造,其中树由MixedStyledText(节点)和SingleStyledText(叶)对象形成.这些spans()方法产生SingleStyledText实例.后者可以取决于外部参数.例如,它们被呈现的页码.这些目前被视为特例.
这是第二个选项的开始
from types import GeneratorType
def gen_wrapper(func):
def _inner(*args):
try:
if args:
if isinstance(args[0], GeneratorType):
func.gen = getattr(func, 'gen', args[0])
func.recall = next(func.gen)
try:
return func.recall
except AttributeError:
func.recall = next(func.gen)
return func.recall
except StopIteration:
pass
return _inner
@gen_wrapper
def Gen_recall(*args):
pass
Run Code Online (Sandbox Code Playgroud)