【问题标题】:How to get return value from coroutine in python如何从python中的协程中获取返回值
【发布时间】:2013-09-07 19:13:52
【问题描述】:

我正在根据http://www.dabeaz.com/coroutines/Coroutines.pdf尝试协程管道

问题是,我怎样才能从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 而不是生成器。

那我该如何获取返回值呢?

【问题讨论】:

    标签: python generator coroutine


    【解决方案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)]
    

    【讨论】:

    • 假设我推入值A和值B,经过过滤、广播、处理等,A生成10个值到sink,B生成8个值到sink。我想要 A 的最大值和 B 的最大值,但是我该如何判断哪个值是从 A 生成的还是从 B 生成的呢?关于如何在水槽中做到这一点的任何想法?
    • @lxyu 您可以发送一个键来知道哪个生产者产生了一个值,而接收器可以有一个状态来知道哪些值在哪里发送以及哪个值是最大值。查看我的编辑。
    • 我建议发送一个封装了你需要的所有数据的对象!
    猜你喜欢
    • 1970-01-01
    • 2011-10-17
    • 2018-04-15
    • 1970-01-01
    • 1970-01-01
    • 2018-02-16
    相关资源
    最近更新 更多