Does anyone know a pythonic way of iterating over the elements of a Queue.Queue without removing them from the Queue. I have a producer/consumer-type program where items to be processed are passed by using a Queue.Queue, and I want to be able to print what the remaining items are. Any ideas?
5 Answers
You can loop over a copy of the underlying data store:
for elem in list(q.queue)
Eventhough this bypasses the locks for Queue objects, the list copy is an atomic operation and it should work out fine.
If you want to keep the locks, why not pull all the tasks out of the queue, make your list copy, and then put them back.
mycopy = []
while True:
try:
elem = q.get(block=False)
except Empty:
break
else:
mycopy.append(elem)
for elem in mycopy:
q.put(elem)
for elem in mycopy:
# do something with the elements
3 Comments
for elem in list(q.queue) results in TypeError: 'Queue' object is not iterable in Python 3. Perhaps I am doing something wrong?for elem in list(q.queue.queue).I have implemented an IterableQueue(asyncio.Queue) that supports async for iteration. See pyutils in GitHub.
from pyutils import IterableQueue
from asyncio import run, Task, create_task
async def producer(Q: IterableQueue[int], n: int) -> None:
await Q.add_producer(N=1)
for i in range(n):
await Q.put(i)
await Q.finish()
return None
async def amain():
q : IterableQueue[int] = IterableQueue(maxsize=5)
task : Task = create_task(producer(q, 10))
# Iterate over queue items
async for i in q:
print(f"Got {i}")
if __name__ == "__main__":
run(amain())
IterableQueue() counts producers with add_producer(). Once the last producers finishes (finish()) then a sentinel value (None) is added to the queue marking the queue end.