У меня есть древовидная структура объектов. Мне нужно перебирать все элементы ( "значения" ) в листьях. Для этого я сейчас использую методы генератора, как показано ниже:
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
(node) и SingleStyledText
(leaf ) объекты. Методы spans()
дают экземпляры SingleStyledText
. Последнее может зависеть от внешних параметров. Например, номер страницы, на которую они отображаются. В настоящее время они рассматриваются как особый случай.