Reputation: 23
i'm trying to build a pipeline of some math operations, based on user input and try to print the acumulation result for this operations. For example the input would be a list of operations, then the number of numeric inputs and then numbers like this:
[square, accumulate]
3
1
2
3
This should return something like:
1
5
14
First it prints 1 as 1*1, then it adds up that 1 to the result of 2*2 giving 5, then adds it to the 3*3 giving 14. But there's something wrong with my approach, the second number input always turns into a None value and I don't know why. I'm stuck getting:
1
None
10
Any ideas? Here is my code:
import math
import os
import random
import re
import sys
def printer():
while True:
x = yield
print(x)
def co_generator(n):
for _ in range(n):
x = int(input())
yield x
def get_root():
while True:
number = (yield)
yield math.floor(math.sqrt(number))
def get_square():
number = 0
while True:
number = (yield)
yield number**2
def accumulator():
acum = 0
while True:
acum += (yield)
yield acum
def operations_pipeline(numbers, operations, print_acum):
for num in numbers:
for i, w in enumerate(operations):
num = w.send(num)
print_acum.send(num)
for operation in operations:
operation.close()
print_acum.close()
if __name__ == '__main__':
order = input().strip()
n = int(input())
numbers = co_generator(n)
print_acum = printer()
next(print_acum)
root = get_root()
next(root)
accumulate = accumulator()
next(accumulate)
square = get_square()
next(square)
operations_pipeline(numbers, eval(order), print_acum)
Upvotes: 2
Views: 2971
Reputation: 21
def rooter():
number=0
while True:
number= yield math.floor(math.sqrt(number))
def squarer():
number=0
while True:
number= yield number**2
yield will give none try this way
def accumulator():
number=0
while True:
number+= yield number
Upvotes: 2
Reputation: 280465
You're writing your code as if (yield)
receives a value and yield whatever
sends one. That's not how it works. All yield
s both send a value and receive one.
When a generator executes a yield
, it does so in two phases. First, the argument of the yield
becomes the return value of the current next
or send
call, and the generator suspends execution. If there is no argument, None
is used. That's where your None
s are coming from
Second, when another next
or send
is executed, the generator unsuspends, and the send
argument (or None
if next
was used) becomes the value of the yield
expression.
You're trying to use one yield
to receive a send
argument and another to set send
's return value. You need to use a single yield
to set a send
return value and receive the next send
's argument. For example,
def get_square():
number = 0
while True:
number = yield number**2
Alternatively, if you want to use separate yield
s to send and receive values on the generator's end, then you need to use separate send
(or next
) calls to receive and send values on the other end, and ignore the None
s. For example,
w.send(num)
num = next(w)
instead of num = w.send(num)
, so operations_pipeline
would look like
def operations_pipeline(numbers, operations, print_acum):
for num in numbers:
for w in operations:
w.send(num)
num = next(w)
print_acum.send(num)
for operation in operations:
operation.close()
print_acum.close()
Upvotes: 3
Reputation: 2598
I believe you need to add a call to next
in your operations_pipeline
code here:
def operations_pipeline(numbers, operations, print_acum):
for num in numbers:
for i, w in enumerate(operations):
num = w.send(num)
next(w) # <<<--- this
Without that I don't believe it was ever getting back into get_square
the second time, assuming your first input was [square, accumulate]
.
Upvotes: 0