如何使用 for 循环而不是 while 循环遍历 Python Queue.Queue?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21157739/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 22:11:31  来源:igfitidea点击:

How to iterate through a Python Queue.Queue with a for loop instead of a while loop?

python

提问by majidarif

Normally we code it like this:

通常我们这样编码:

while True:
    job = queue.get()
    ...

But is it also possible to do something in the lines of:

但是否也可以在以下方面做一些事情:

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

The real reason why I want to do that is because I wanted to use python-progressbar's auto detect maxval. They do it like for this in progressbar(that):

我想要这样做的真正原因是因为我想使用 python-progressbar 的自动检测 maxval。他们这样做for this in progressbar(that):

采纳答案by falsetru

You can use iterwith callable. (You should pass two arguments, one for the callable, the other for the sentinel value)

您可以iter与可调用一起使用。(您应该传递两个参数,一个用于可调用对象,另一个用于标记值)

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

NOTEThis will block when no elements remain and no sentinel value is put. Also, like a while-getloop and unlike normal forloops over containers, it will remove items from the queue.

注意当没有元素剩余并且没有放置哨兵值时,这将阻塞。此外,与while-get循环一样,与for容器上的普通循环不同,它将从队列中删除项目。

UPDATE: Noneis common value, so here's a sample with more concrete sentinel value:

UPDATE:None是通用值,所以这里有一个更具体的哨兵值的示例:

sentinel = object()
for job in iter(queue.get, sentinel):
    # do stuff with job

回答by James

My first though was for the iter function, but the built in queue module doesn't return a sentinel, so a good alternative might be to define your own wrapper class:

我的第一个虽然是 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

This iterator wraps the queue and yields until the queue is empty, then returns, so now you can do:

这个迭代器包装队列并产生直到队列为空,然后返回,所以现在你可以这样做:

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

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

Output:

输出:

1
2
3

This method is a bit verbose it would be interesting if anyone knows anything better using the builtins.

这种方法有点冗长,如果有人使用内置函数更好地了解它会很有趣。

回答by Alfe

For that kind of queue actually I would not typically use this check of queue.empty()because I always use it in a threaded context and thus cannot know whether another thread would put something in there in a few milliseconds (thus that check would be useless anyway). I never check a queue for being empty. I rather use a sentinel value which marks the ending of a producer.

对于这种队列,实际上我通常不会使用这种检查,queue.empty()因为我总是在线程上下文中使用它,因此无法知道另一个线程是否会在几毫秒内将某些内容放入其中(因此该检查无论如何都是无用的)。我从不检查队列是否为空。我宁愿使用标记生产者结束的哨兵值。

So using the iter(queue.get, Sentinel)is more what I like.

所以使用iter(queue.get, Sentinel)是我更喜欢的。

If you knowthat no other thread will put items in the queue anymore and just want to drain it from all currently contained items, then you can use sth like this:

如果您知道没有其他线程将不再将项目放入队列中并且只想从当前包含的所有项目中排出它,那么您可以像这样使用 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)

or

或者

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)

回答by shakil18

I would say this is an easy way to iterate over queue in some points:

我会说这是在某些方面迭代队列的简单方法:

from queue import Queue

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

for i in q.queue:
    print(i)