首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >协程程序上的itertools.tee?

协程程序上的itertools.tee?
EN

Stack Overflow用户
提问于 2014-05-01 06:10:40
回答 3查看 649关注 0票数 16

我有一个对象的树形结构。我需要遍历叶子中的所有项(“值”)。为此,我目前使用生成器方法,如下所示:

代码语言:javascript
复制
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)

这将打印:

代码语言:javascript
复制
1
1
2
2
3
3

现在,Leaf返回的值将依赖于外部参数。我在考虑使用协程来将此参数向下传递到叶子节点:

代码语言:javascript
复制
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

这段代码一点也不美观,但它是有效的。它打印:

代码语言:javascript
复制
1A
1B
2C
2D
3E
3F

然而,这个解决方案存在一个问题。我广泛地使用了itertools.tee (和chain)来方便地保存迭代器的状态,以防我需要回溯。我希望这些也能在协程中起作用,但是不幸的是,没有这样的运气。

我目前正在考虑的一些替代解决方案:

  • 具有生成器生成函数(闭包),这些函数接受外部parameter
  • write自定义类来模拟具有保存状态

功能的协程

第一种选择似乎是最有吸引力的。但也许还有更好的选择?

一些上下文:我在RinohType中使用了这个结构,其中树由MixedStyledText (节点)和SingleStyledText (叶)对象构成。spans()方法生成SingleStyledText实例。后者可以依赖于外部参数。例如,它们要渲染到的页码。这些目前被视为特例。

EN

回答 3

Stack Overflow用户

发布于 2015-01-30 12:59:12

我尽可能地让函数返回简单的数据结构。在这种情况下,

代码我会让每个节点生成一个简单的字典(或者,在RinohType的情况下,是一个SingleStyledTextConfig对象或namedtuple)。这个实现将像以前一样很好地处理itertools,因为它只是将数据转换为其他数据。

  • 我会转换这个对象集合以说明外部参数(如页面代码),我将使用配置数据的集合来实际创建输出(在RinohType的情况下,是<代码>D11对象)。<代码>H212<代码>F213

在更高的层次上:您提出的解决方案(据我所知,您的简化版本)是在的同时尝试做太多事情的。它试图在一个步骤中配置对象创建,调整配置,并基于该配置创建对象。如果您分离了这些关注点,您的实现将会更简单,更好地使用itertools,并且更容易测试。

有关这种思考的更详细的论述,请参阅Gary Bernhardt's talkBrandon Rhodes' talk on the Clean Architecture in Python (当然还有他们在演讲中提到的资源)。

票数 1
EN

Stack Overflow用户

发布于 2014-05-23 06:13:12

这是第二个选项的开始

代码语言:javascript
复制
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                    
票数 0
EN

Stack Overflow用户

发布于 2014-05-28 01:23:03

我不确定我是否正确理解了这个问题。是否需要Leaf2来进行计算?如果不是,则可以执行以下操作:

代码语言:javascript
复制
import itertools

class Node2(object):
    def __init__(self):
        self.items = [Leaf2(1), Leaf2(2), Leaf2(3)]

    def values(self):
        for item in self.items:
            for value in item.values():
                yield value

class Leaf2(object):
    def __init__(self, value):
        self.value = value

    def values(self):
        for i in range(2):
            yield self.value

def process(i, parameter):
    return '{}{}'.format(i, parameter)

n = Node2()
for value, parameter in zip(n.values(), itertools.count(ord('A'))):
    print(process(value, chr(parameter)))

如果让Leaf2进行处理真的很重要,您可以这样做

代码语言:javascript
复制
class Leaf2:
    def values(self):
        for i in range(2):
            yield self

def process(self, parameter):
    pass

所以基本上你可以这样做

代码语言:javascript
复制
n = Node2()
for node, parameter in zip(n.values(), itertools.count(ord('A'))):
    print(node.process(chr(parameter)))
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23398903

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档