用Python生成器替换c++ STL输出迭代器

Replacing C++ STL output iterator with a Python generator

本文关键字:c++ STL 输出 迭代器 替换 Python      更新时间:2023-10-16

Python没有内置的OutputIterator;特别是,内置或标准库容器不支持任何允许客户端代码在不知道特定容器类型的情况下向它们发送数据的通用接口。

根据@Steven Rumbalski的评论和@Glenn Maynard的回答,这通常不是一个问题,因为在c++中会接受OutputIterator参数的函数,在python中会被简单地写为生成器。

通常情况下,我使用生成器没有问题,并且从来没有觉得我需要在Python中使用OutputIterator。然而,在这种情况下,我被卡住了。

我在Python中重新实现了Boost Graph Library中的一些算法。一个典型的图遍历算法,比如depth_first_search,将一个"访问者"对象作为参数。访问者本质上是一堆回调函数,遍历算法在执行过程中遇到不同的事件(例如,发现一个新的顶点,检查一条边等)时会调用这些回调函数。在c++中,我可以让一个或几个这样的回调函数将数据发送到访问者对象在初始化时从客户机代码获得的OutputIterator对象。(例如,这正是topological_sort是如何实现的:它接受一个OutputIterator,将其传递给dfs_visitor对象,然后访问者对象"监视"事件finished_vertex并将它接收到的顶点发送到指定的OutputIterator。当然,更复杂的情况需要多个OutputIterator对象和多个回调函数。

如何使用Python生成器实现相同的功能?

我需要以某种方式发送数据,在生成器"样式"中,从depth_first_search到多个指定的数据消费者。我只是不知道该怎么做。(我使用Python 3.3.)

你能传递回调函数吗?

def depth_first_search(some_args, on_edge=lambda e:None, on_vertex=lambda v:None):
    ...
    on_edge(some_edge)
    on_vertex(some_vertex)
def edge_handler(e):
    print "E", e
def vertex_handler(v):
    print "V", v
depth_first_search(..., on_edge=edge_handler, on_vertex=vertex_handler)

或生成目的地:

def depth_first_search(some_args, on_edge=lambda e:None, on_vertex=lambda v:None):
    ...
    yield "edge", some_edge
    yield "vertex", some_vertex
for t, value in depth_first_search(...):
    if t == 'edge':
        # ...
    elif t == 'vertex':
        # ...

generator.send方法在这里做你想要的,我认为:

def depth_first_search(some_args, edge_consumer, vertex_consumer):
    # start the generators
    next(edge_consumer)
    next(vertex_consumer)
    ...
    edge_consumer.send(some_edge)
    vertex_consumer.send(some_vertex)
    ...
    # this raises GeneratorExit at the `yield` in the generator
    edge_consumer.close()
    vertex_consumer.close()
def edge_handler():
    while True:
        e = yield
        print "E", e
def vertex_handler():
    while True:
        v = yield
        print "V", v
depth_first_search(..., edge_handler(), vertex_handler())

我不知道这是否可行,但是使用像multimethods这样的库来实现多重分派函数来做您需要的事情怎么样?我的互联网有DNS问题,所以我无法查找语法,所以你会得到伪代码而不是真正的Python,但这里是我所说的一般想法:

def send_to(data, consumer):
    workfunc = dispatch(type(consumer))
    workfunc(data, consumer)
def send_to_list(data, consumer):
    consumer.append(data)
def send_to_set(data, consumer):
    consumer.add(data)
def send_to_file_obj(data, consumer):
    consumer.write(data)

需要一些管道将工作函数连接到调度函数,当然,这是我现在无法查找的,因为我的DNS坏了。(StackOverflow,幸运的是,仍然在我的浏览器缓存)。所以我恐怕这个答案太笼统了,细节太少了,但希望它至少能给你指明一个有用的方向。