Python – Is a coroutine essentially a class?

Is a coroutine essentially a class?… here is a solution to the problem.

Is a coroutine essentially a class?

I am following the instructions to learn coroutines

def grep(pattern):
    print("Looking for %s" % pattern)  # prime it(explain shortly)
    while True:
        line = (yield) # expression
        if pattern in line:
            print(line)

Test it

>>> g = grep("python")
>>> g.next()
Looking for python
>>> g.send("coroutine test")
>>> g.send("learning python")

It seems that the yield expression is executed as functools.partial, excluding that it should be started with next().

At this point, def grep is actually a class grep because it starts a generator object first.

Coroutines are hard to follow, and my understanding of the right direction to continue without further side effects is because python should have her reasons for naming it def instead of class

Solution

It seems that a yield expression perform as a functools.partial, [except that] it should be primed using next().

I’m not sure exactly what makes you say that, but I don’t immediately see the similarities. functools.parital is designed to bind some args/kwargs to callables and let you save other args/kwargs for users to invoke. (“partial() is used in partial function applications that ‘stuck’ certain parts of function parameters and/or keywords, resulting in new objects with simplified signatures.”) It’s not really a matter of using this generator or any generator.

The coroutine is tricky to follow, is my understanding on the right direction to continue without further side-effects since Python named it def rather than class ?

They are cunning and agree with you. But I’m not sure if I see a coroutine “essentially like a class”. Coroutines are specialized generators. Generators are defined with def and have the ability to pause and resume their execution. This describes generators, not classes, and simply replacing def with class is syntactically invalid for starters.

One way you can think of any expression like a = yield b is to mark a breakpoint.

When you call next(g), it continues to advance until it encounters the yield statement and then stops there. It pushes the resulting value to the call stack, but it pauses execution and stops there, which can resume when you call next() on it again. (This is the key difference between functions and generators and between functions and coroutines, by extension.) )

On the first call to next(), line is None. (Basically, line = yield None.) You won’t be able to iterate on this because you can’t say for pattern in None. In this case, “start” might mean that the initial call to next(g) is similar to g.send(None).

Now, when you send other values to the generator, they will be assigned to line, and pattern is still “python”. If “python” is found in .send(), it will be printed.

>>> g = grep("python")
>>> n = g.send(None)  # equiv to next(g); stop at line = (yield)
Looking for python
>>> n is None
True
>>> g.send("coroutine test")
>>> g.send("coroutine test")
>>> g.send("coroutine test")  # no match
>>> g.send("learning python") # match
learning python
>>> g.send("python3.7") # match
python3.7

Related Problems and Solutions