I have a tree structure of objects. I need to iterate over all the items ("values") in the leaves. For this I'm currently using generator methods as illustrated below:
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)
This prints:
1
1
2
2
3
3
Now, the values returned by a Leaf
will depend on an external parameter. I was thinking of employing coroutines to be able to pass this parameter down to the leaf nodes:
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
This code is far from pretty, but it works. It prints:
1A
1B
2C
2D
3E
3F
There's a problem with this solution though. I was using itertools.tee
(and chain
) extensively to easily save the state of the iterator in case I needed to backtrack. I was hoping these would work on coroutines as well, but alas, no such luck.
Some alternative solutions I'm considering at the moment:
- have the generators yield functions (closures) that accept the external parameter
- write custom classes to emulate coroutines with capabilities for saving state
The first option seems the most attractive. But perhaps there are better options?
Some context: I'm using this construct in RinohType where the tree is formed by MixedStyledText
(node) and SingleStyledText
(leaf) objects. The spans()
methods yield SingleStyledText
instances. The latter can be dependent on external parameters. For example, the page number they are being rendered to. These are currently treated as a special case.