关于协程的itertools.tee?

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实例.后者可以取决于外部参数.例如,它们被呈现的页码.这些目前被视为特例.

cdh*_*ann 0

这是第二个选项的开始

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)