Как выполнить итерацию через Queue.Queue Python с циклом for вместо цикла while?

Обычно мы кодируем его так:

while not queue.empty():
  try:
    job = queue.get()

Но возможно ли что-то сделать в строках:

for job in queue.get():
    #do stuff to job

Настоящая причина, по которой я хочу это сделать, - это то, что я хотел использовать maxval. Они делают это как for this in progressbar(that):

Ответы

Ответ 1

Вы можете использовать iter с возможностью вызова. (Вы должны передать два аргумента, один для вызываемого, другой для значения дозорного)

for job in iter(queue.get, None): # Replace `None` as you need.
    # do stuff with job

ПРИМЕЧАНИЕ Это будет заблокировано, если элемент не останется и не будет отправлено значение дозорного значения.

Ответ 2

Для такой очереди я обычно не использовал бы эту проверку queue.empty(), потому что я всегда использую ее в поточном контексте и, следовательно, не могу знать, будет ли другой поток помещать что-то там за несколько миллисекунд (таким образом, чтобы проверка быть бесполезным в любом случае). Я никогда не проверяю очередь на то, чтобы быть пустым. Я скорее использую значение сторожевого знака, которое знаменует окончание продюсера.

Таким образом, использование iter(queue.get, Sentinel) больше того, что мне нравится.

Если вы знаете, что ни один другой поток больше не будет помещать элементы в очередь и просто хочет вытереть его из всех содержащихся в данный момент элементов, вы можете использовать sth следующим образом:

class Drainer(object):
  def __init__(self, q):
    self.q = q
  def __iter__(self):
    while True:
      try:
        yield self.q.get_nowait()
      except queue.Empty:  # on python 2 use Queue.Empty
        break

for item in Drainer(q):
  print(item)

или

def drain(q):
  while True:
    try:
      yield q.get_nowait()
    except queue.Empty:  # on python 2 use Queue.Empty
      break

for item in drain(q):
  print(item)

Ответ 3

Мое первое, хотя было для функции iter, но встроенный модуль очереди не возвращает дозорный сигнал, поэтому хорошей альтернативой может быть определение вашего собственного класса-оболочки:

import Queue

class IterableQueue():
    def __init__(self,source_queue):
            self.source_queue = source_queue
    def __iter__(self):
        while True:
            try:
               yield self.source_queue.get_nowait()
            except Queue.Empty:
               return

Этот итератор обертывает очередь и возвращает до тех пор, пока очередь не будет пустой, а затем вернется, так что теперь вы можете сделать:

q = Queue.Queue()
q.put(1)
q.put(2)
q.put(3)

for n in IterableQueue(q):
    print(n)

Вывод:

1
2
3

Этот метод немного подробный, было бы интересно, если кто-нибудь знает что-нибудь лучше, используя встроенные функции.

Ответ 5

Для стандартного итеративного объекта Python вы можете просто использовать:

for job in queue:
    #do stuff to job