My guess is that it is only possible to do something like this:
def adder(producer1, producer2, consumers):
while True:
x = next(producer1)
y = next(producer2)
for consumer in consumers:
consumer.send(x+y)
and then just call adder(x_producer, y_producer, consumers)
. As you can see from the diagram:
the adder can't be placed in the middle of the pipeline and the reason for that is that it has to have all references to consumers and producers, which is possible if we call the adder at the highest level.
UPDATE: here is another approach, which makes adder a generator:
class AdderWithBroadcast(object):
consumers = []
def __init__(self, x_prod, y_prod):
self.x_prod = x_prod
self.y_prod = y_prod
def __iter__(self):
return self
def next(self):
x = next(self.x_prod)
y = next(self.y_prod)
for consumer in self.consumers:
consumer.send(x+y)
return x+y
def consumer():
while True:
a = (yield)
print a, ' in consumer'
k = iter(range(10))
adder = AdderWithBroadcast(k, k)
cons = consumer()
cons.send(None)
adder.consumers.append(cons)
for i in adder:
# I won't include the actual result here, you can try in no your own
print i
Decorator approach:
class Broadcaster(object):
consumers = []
def __init__(self, gen):
self.gen = gen
def __iter__(self):
return self
def __call__(self, *args, **kwargs):
self.gen = self.gen(*args, **kwargs)
def next(self):
yielded = next(self.gen)
for consumer in self.consumers:
consumer.send(yielded)
return yielded
@Broadcaster
def adder(producer1, producer2):
while True:
x = next(producer1)
y = next(producer2)
yield x + y
# result is the same as in previous solution