turning callback into generator

Peter Otten __peter__ at web.de
Tue Sep 7 04:15:55 EDT 2004


Bengt Richter wrote:

> Not that familiar with python threads and queue, but here's a start:
> 
>  >>> import threading
>  >>> import Queue
>  >>> q = Queue.Queue(3) # ridiculously short

But already too long if the items yielded are somehow interdependant.

>  >>>
>  >>> def producer(n, cb):
>  ...     for i in xrange(n): cb(i)
>  ...
>  >>> def product_generator(p, *a, **kw):
>  ...     tpq = threading.Thread(target=p, args=a, kwargs=kw)
>  ...     tpq.start()
>  ...     try:
>  ...         while True: yield q.get(True,5)
>  ...     except Queue.Empty:
>  ...         print 'No data for 5 seconds'
>  ...
>  >>> for item in product_generator(producer, 8, q.put): print item
>  ...
>  0
>  1
>  2
>  3
>  4
>  5
>  6
>  7
>  No data for 5 seconds
>  >>>
> 
> Not tested beyond what you see ;-)

The problem is _not_ to signal that there are no more items to be expected -
you can easily do that by wrapping the producer to put a special object
into the queue when it's done and test for that in the product_generator().
This would avoid the 5-second jet lag. It's a bit harder to avoid a
dangling thread when you have code like

for item in product_generator(...): 
   if pred(item): break

You could attack that with a long timeout for Queue.put(), too, but I'd
rather signal the generator that we're done (via a second Queue, maybe).
Unfortunately this imposes changes on the client code, thus defeating the
original goal of making generators and visitors/callbacks freely
interchangeable.

Peter







More information about the Python-list mailing list