Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a coroutine yield values in Python?

So I understand how generators and coroutines work. Broadly speaking, generators produce data and coroutines consume data. Now, what I am trying to do is combine both these features.

I have defined a coroutine that receives a list as an input and then tries to **yield** items from the list one at a time, like a generator would do.

Here is my code -

def coroutine():
    print('Starting coroutine')
    value = (yield)
    for i in value:
        yield i



c=coroutine()
c.__next__()
c.send([1,2,3,4,5])


for val in c:
    print(val)

The problem is, the first list item is being lost. The value 1 is not being returned from the coroutine.

Based on my understanding, the flow should have been as follows.

  1. c=coroutine() ----> Declares the coroutine without starting it.
  2. c.__next__() ----> This starts the coroutine and it advances to the line - value = (yield) and stops there.
  3. c.send([1,2,3,4,5]) ----> This passes the new list to the waiting coroutine i.e value = (yield). The coroutine now proceeds to the next yield statement inside the for loop.
  4. The for loop in the main program is supposed to receive each items of the list that it initially passed. But this does not happen.

Can you please explain why ? The reason I am trying to do this is to generate a pipeline. Each component will receive items, modify it and then yield it to the next coroutine in the pipeline.

Please help.

EDIT --------------------

The output is as follows -

Starting coroutine
2
3
4
5
like image 793
Boudhayan Dev Avatar asked Oct 28 '25 23:10

Boudhayan Dev


1 Answers

You are missing that when calling to send, the corrutine will go till the next yield and that one will be called, so, if you do :

c=coroutine()
c.__next__()
print(c.send([1,2,3,4,5]))


for val in c:
    print(val)

You will see how the missing value is printed (as it is yielded in the send call)

Here you have the live example

For the behaviour you desire you can add an extra yield statement to the corrutine:

def coroutine():
    print('Starting coroutine')
    value = (yield)
    yield
    for i in value:
        yield i
like image 149
Netwave Avatar answered Oct 30 '25 14:10

Netwave