A Coroutine is generator which is capable of constantly receiving input data, process input data and may or may not return any output.
Coroutines are majorly used to build better Data Processing Pipelines.
Similar to a generator, execution of a coroutine stops when it reaches yield
statement.
A Coroutine uses send
method to send any input value, which is captured by yield
expression.
Syntax - Usage
# Syntax
# Declaredef coroutine_function(): while True: data = yield # any data operations print(f'Name: {data} \nLength: {len(data)}')
# Initiatec = coroutine_function()next(c)
# Usagec.send('Vijay Anand')c.close()
Output
Name: Vijay AnandLength: 11
Coroutine - Example...
As seen in Example1 and Example2, passing input to coroutine is possible only after the first next function call.
Example - 1
# coroutine -> 1def string_parser(func): while True: name = yield for x in name.split(): func.send(x)
# coroutine -> 2def string_length(): while True: string = yield print("Length of '{}' : {}".format(string, len(string)))
f = string_length()next(f)
s = string_parser(f)next(s)s.send('Jack Black')
Output
Length of 'Jack' : 4Length of 'Black' : 5
Many programmers may forget to do so, which results in error.
Such a scenario can be avoided using a decorator as shown in Example 3.
Version - 1
def TokenIssuer(): tokenId = 0 while True: name = yield tokenId += 1 print('Token number of', name, ':', tokenId)
t = TokenIssuer()next(t)t.send('George')t.send('Rosy')t.send('Smith')
Output
Token number of George : 1Token number of Rosy : 2Token number of Smith : 3
Version - 2
def TokenIssuer(tokenId=0): try: while True: name = yield tokenId += 1 print('Token number of', name, ':', tokenId) except GeneratorExit: print('Last issued Token is :', tokenId)
t = TokenIssuer(100)next(t)t.send('George')t.send('Rosy')t.send('Smith')t.close()
Output
Token number of George : 101Token number of Rosy : 102Token number of Smith : 103
Version - 3
def coroutine_decorator(func): def wrapper(*args, **kwdargs): c = func(*args, **kwdargs) next(c) return c
return wrapper
@coroutine_decoratordef TokenIssuer(tokenId=0): try: while True: name = yield tokenId += 1 print('Token number of', name, ':', tokenId) except GeneratorExit: print('Last issued Token is :', tokenId)
t = TokenIssuer(100)t.send('George')t.send('Rosy')t.send('Smith')t.close()
output
Token number of George : 101Token number of Rosy : 102Token number of Smith : 103Last issued Token is : 103
Double yield
in a single coroutine
def nameFeeder(): while True: fname = yield print('First Name:', fname) lname = yield print('Last Name:', lname)
n = nameFeeder()next(n)n.send('George')n.send('Williams')n.send('John')n.close()
output
First Name: GeorgeLast Name: WilliamsFirst Name: John
next()
error scenario without starting generator
def stringDisplay(): while True: s = yield print(s * 3)
c = stringDisplay()c.send('Hi!!') # TypeError: can't send non-None value to a just-started
Output
Traceback (most recent call last): File "C:\Users\hai\AppData\Roaming\JetBrains\PyCharmCE2021.2\scratches\coroutine.py", line 138, in <module> c.send('Hi!!') # TypeError: can't send non-None value to a just-startedTypeError: can't send non-None value to a just-started generator
Best Example for Coroutine Program in Python
#!/bin/python3
import sys
# Define the function 'coroutine_decorator' belowdef coroutine_decorator(coroutine_func): def wrapper(*args, **kwdargs): c = coroutine_func(*args, **kwdargs) next(c) return c
return wrapper
# Define the coroutine function 'linear_equation' below@coroutine_decoratordef linear_equation(a, b): while True: x = yield print("Expression, {}*x^2 + {}, with x being {} equals {:.2f}".format(a, b, x, a * x ** 2 + b))
# Define the coroutine function 'numberParser' below@coroutine_decoratordef numberParser(): while True: x = yield equation1 = linear_equation(3, 4) equation1.send(x) equation2 = linear_equation(2, -1) equation2.send(x) # code to send the input number to both the linear equations
def main(x): n = numberParser() n.send(x)
if __name__ == "__main__": x = float(input("Enter the x value in float: ")) res = main(x)
Output
Enter the x value in float: 2.4Expression, 3*x^2 + 4, with x being 2.4 equals 21.28Expression, 2*x^2 + -1, with x being 2.4 equals 10.52