lettura simple

Coroutines in Python

Coroutines are specialized functions designed to pause their execution at a yield statement, and then seamlessly resume where they left off upon their next invocation.

How do coroutines differ from generators? Both maintain their local namespace—meaning they remember the values of local variables between executions. The key difference is that while generators send a value back to their caller, coroutines can also receive values, effectively consuming them.

For coroutines, the yield statement is typically placed on the right side of an assignment

x = (yield)

or used as an individual statement.

yield

Understanding Coroutines

Initiating a coroutine returns a generator object. This object can be manipulated using two primary methods:

  • send()
    Continues the coroutine's execution by passing it a value.
  • __next__()
    Proceeds with the coroutine's execution without supplying a value.

The Purpose of Coroutines Coroutines are pivotal for asynchronous programming. They enable you to suspend and resume functions at precise points, simplifying the management of concurrent and asynchronous tasks in applications that leverage multithreading or event-driven architectures.

Using the __next__() Method

The __next__() method allows for coroutine invocation without needing to pass a consumable value.

object.__next__()

Here’s a practical example for clarity.

Define the following coroutine function:

def countdown():
    n=10
    while n > 0:
        yield
        n -= 1
        print(n)

This coroutine, named "countdown()", pauses at each yield statement until the next call.

To start, instantiate the coroutine within an object:

x = countdown()

The initial call using __next__() sets up the function and halts at the first yield encountered, assigning the number 10 to n.

x.__next__()

Subsequent calls with __next__() resume after each yield, decrement n by one, and output the result.

x.__next__()

9

Thus, with every iteration, the coroutine pauses at yield, awaiting the next activation to continue.

x.__next__()

8

Notice how each invocation of countdown() picks up right where it left off, retaining all local variable values.

Interacting with Coroutines via the send() Method

The send() method enables you to resume coroutine execution by passing a specific value it can process.

object.send()

Consider another practical example:

Create this coroutine incorporating two yield instructions within its structure.

def countdown():
    # receives a value from the call
    n=yield
    while n > 0:
        # waits for the next call
        yield
        n -= 1
        print(n)

The initial yield instruction is designed to await a value for consumption, whereas the subsequent yield instruction proceeds to consume the provided value.

To utilize it, create a generator from the coroutine:

object = countdown()

Begin by initiating the generator with a send(None) call:

object.send(None)

Alternatively, initiate the generator with the next function for simplicity.

next(object)

Now, you're ready to send a consumable value to the coroutine using send().

For instance, sending the value 10:

object.send(10)

Upon receiving 10, the coroutine assigns it to n and resumes, pausing only when another yield is encountered.

To proceed, invoke the coroutine again with either send() or __next__().

object.__next__()

The coroutine continues from yield, deducts from n, and displays the outcome.

9

With each loop iteration, the coroutine pauses at yield, awaiting your next command.

object.__next__()

8

Every call methodically decreases n's value and prints the ensuing figure.

To gracefully conclude the coroutine, invoke the close() method.

object.close()




Report a mistake or post a question




FacebookTwitterLinkedinLinkedin