【发布时间】:2014-06-17 09:53:33
【问题描述】:
我有一个对象的树形结构。我需要遍历叶子中的所有项目(“值”)。为此,我目前正在使用如下图所示的生成器方法:
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)
打印出来:
1
1
2
2
3
3
现在,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
这段代码远非漂亮,但它确实有效。它打印:
1A
1B
2C
2D
3E
3F
但是这个解决方案有问题。我广泛使用itertools.tee(和chain)来轻松保存迭代器的状态,以防我需要回溯。我希望这些也能在协程上工作,但可惜,没有这样的运气。
我目前正在考虑的一些替代解决方案:
- 让生成器产生接受外部参数的函数(闭包)
- 编写自定义类来模拟具有保存状态功能的协程
第一个选项似乎最有吸引力。但也许有更好的选择?
一些上下文:我在RinohType 中使用此构造,其中树由MixedStyledText(节点)和SingleStyledText(叶)对象组成。 spans() 方法产生 SingleStyledText 实例。后者可以依赖于外部参数。例如,它们被呈现到的页码。这些目前被视为特殊情况。
【问题讨论】:
-
你用的是什么版本的 Python?
-
@GamesBrainiac 我正在 Python 3.4 上开发,但最终可能会向后移植到 2.7(2.7 和 3.x 的单一代码库)。你问什么特别的原因?
-
听起来像是可以应用访问者模式的地方——你考虑过吗?
标签: python generator itertools coroutine tee