如何从python中的coroutine获取返回值

时间:2013-09-04 10:16:06

标签: python generator coroutine

我正在根据http://www.dabeaz.com/coroutines/Coroutines.pdf

尝试coroutines管道

问题是,如何从sink获取价值而不是仅打印它?

以此代码为例

def coroutine(func):
    def start(*args, **kwargs):
        cr = func(*args, **kwargs)
        next(cr)
        return cr
    return start


@coroutine
def produce(target):
    while True:
        n = (yield)
        target.send(n*10)


@coroutine
def sink():
    try:
        while True:
            n = (yield)
            print(n)
    except GeneratorExit:
        pass


sk = sink()
pipe = produce(sink())

使用此代码我得到:

>>> pipe.send(10)
100

然后我想得到返回值而不是打印它,我试图从接收器中产生:

@coroutine
def sink():
    try:
        while True:
            yield (yield)
    except GeneratorExit:
        pass

但似乎无效,pipe.send(10)仍然会返回None而不是生成器。

那么如何获得返回值?

1 个答案:

答案 0 :(得分:1)

pipe.send为什么要返回生成器?你打算用返回值做什么?

无论是什么,都应该在sink中完成。

但是,您可以将功能更改为

@coroutine
def produce(target):
    while True:
        n = (yield)
        yield target.send(n*10)

@coroutine
def sink():
    try:
        while True:
            yield (yield)
    except GeneratorExit:
        pass

产生target产生的值,因此pipe.send(10)只返回100而不是打印它。

但现在你把生产者和消费者混在一起,这可能会给你带来一些麻烦。


回应你的评论:

from collections import defaultdict

def coroutine(func):
    def start(*args, **kwargs):
        cr = func(*args, **kwargs)
        next(cr)
        return cr
    return start

@coroutine
def produce(key, target):
    while True:
        n = (yield)
        target.send((key, n*10))

class Sink(object):

    def __init__(self):
        self.d = defaultdict(lambda: None)
        self.co = self.sink()

    def send(self, *args):
        self.co.send(*args)

    @coroutine
    def sink(self):
        try:
            while True:
                key, n = yield
                self.d[key] = max(self.d[key], n)
        except GeneratorExit:
            pass


sk = Sink()
pipeA = produce("A", sk)
pipeB = produce("B", sk)

pipeA.send(10)
pipeA.send(20)
pipeA.send(40)

pipeB.send(20)
pipeB.send(40)
pipeB.send(60)

print sk.d.items() # [('A', 400), ('B', 600)]