我有一个对象的树形结构。我需要遍历叶子中的所有项(“值”)。为此,我目前使用生成器方法,如下所示:
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
实例。后者可以依赖于外部参数。例如,它们要渲染到的页码。这些目前被视为特例。
发布于 2015-01-30 12:59:12
我尽可能地让函数返回简单的数据结构。在这种情况下,
代码我会让每个节点生成一个简单的字典(或者,在RinohType
的情况下,是一个SingleStyledTextConfig
对象或namedtuple
)。这个实现将像以前一样很好地处理itertools
,因为它只是将数据转换为其他数据。
RinohType
的情况下,是<代码>D11对象)。<代码>H212<代码>F213在更高的层次上:您提出的解决方案(据我所知,您的简化版本)是在的同时尝试做太多事情的。它试图在一个步骤中配置对象创建,调整配置,并基于该配置创建对象。如果您分离了这些关注点,您的实现将会更简单,更好地使用itertools
,并且更容易测试。
有关这种思考的更详细的论述,请参阅Gary Bernhardt's talk和Brandon Rhodes' talk on the Clean Architecture in Python (当然还有他们在演讲中提到的资源)。
发布于 2014-05-23 06:13:12
这是第二个选项的开始
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
发布于 2014-05-28 01:23:03
我不确定我是否正确理解了这个问题。是否需要Leaf2来进行计算?如果不是,则可以执行以下操作:
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进行处理真的很重要,您可以这样做
class Leaf2:
def values(self):
for i in range(2):
yield self
def process(self, parameter):
pass
所以基本上你可以这样做
n = Node2()
for node, parameter in zip(n.values(), itertools.count(ord('A'))):
print(node.process(chr(parameter)))
https://stackoverflow.com/questions/23398903
复制相似问题