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 usingnext()
.
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 thanclass
?
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