如何使回调类可迭代而不是存储所有回调参数

时间:2015-03-25 09:44:39

标签: python callback iterator coroutine

我有一个带有解析器的第三方库,它需要一个带有new_token方法的回调类。到目前为止,我的回调类和我的令牌处理如下所示:

class MySink(object):
    def __init__(self):
        self.tokens = []

    def new_token(self, token):
        self.tokens.append(token)

sink = MySink()
p = ThirdPartyParser(sink)
p.parse("my_data_file")

for t in sink.tokens:
    print t

令牌列表可能会变得很长(导致内存问题)所以我想将MySink变成一个可迭代的类,其中令牌不必存储在列表中但是被“拉”在处理令牌时停止解析。像这样:

class MyIterableSink(object): # incomplete!
    def new_token(self, token):
        # TODO:
        # Store token for next iteration step
        # halt execution like with 'yield', wait for next iteration step

sink = MyIterableSink()
p = ThirdPartyParser(sink)
p.parse("my_data_file")

for t in sink:
    print t

如何修改MyIterableSink课程?这样的事情可能吗?我无法修改解析器类,只能修改回调类。我知道我必须实现__iter____next__方法并使用协同程序,其中可能使用send方法发送令牌,但不能完全绕过它。任何代码示例都将不胜感激。

2 个答案:

答案 0 :(得分:1)

该行

p.parse("my_data_file")

必须在循环中调用new_token。由于您无法改变第三方解析器的工作方式,因此您无法控制new_token被调用的方式。由于MySink没有迭代p.parse,因此使sink迭代器无效。因此,不要将sink设为迭代器,只需在调用new_token时处理标记:

class MySink(object): 
    def new_token(self, token):
        # process token
        print(token)

sink = MyIterableSink()
p = ThirdPartyParser(sink)
p.parse("my_data_file")

答案 1 :(得分:0)

如果回调是异步的,您可以使用Queue

class MySink(object):
    def __init__(self):
         self.tokens = Queue()

    def new_token(self, token):
        self.tokens.put(token)

    def __iter__(self):
        token = self.tokens.get()
        while token is not None:
            yield token
            token = self.tokens.get()

请注意,您必须为迭代器指定停止条件,例如超时或特殊标记值(上例中的None)。

编辑: 由于你的回调是同步的,unutbu在他的answer中说了这一切。