使用带有“with”语句的Python Queue

时间:2013-10-18 16:45:42

标签: python python-2.7

Queue语句中是否有使用Python with的标准方法?这就是我希望能够使用它的方式:

import Queue
myqueue = Queue.Queue()
...
...
...
with myqueue as nextItem:
    doStuff(nextItem)

__enter__个对象没有__exit__Queue方法,所以这不起作用。是否有任何语法糖使它看起来比这更好?

import Queue
myqueue = Queue.Queue()
...
...
...
try:
    nextItem = myqueue.get()
    doStuff(nextItem)
finally:
    myqueue.task_done()

编辑:在这种情况下,我有两个理由想要使用with语句。首先,我认为with语句可以帮助我的代码更清晰一点,特别是当不仅仅是对doStuff的单个调用时。其次,有一些简单的东西,我可以习惯每次使用,这将确保我不会忘记调用task_done或有一个错误可能导致调用的情况被跳过。

2 个答案:

答案 0 :(得分:1)

似乎答案是否定的 - 没有内置的方法来做到这一点。

然而,正如提到的sweeneyrod,可以继承Queue并添加__enter____exit__方法。这看起来像这样:

import Queue

class MyQueue(Queue.Queue):
    def __enter__(self):
        return self.get()

    def __exit__(self, excType, excValue, traceback):
        self.task_done()

这将允许像我上面所示的那样使用它,尽管这有一个问题,即它将队列视为一项任务。为了解决这个问题,我们可以使用contextlib创建一个充当上下文管理器的方法。

import Queue
from contextlib import contextmanager

class MyQueue(Queue.Queue):
    @contextmanager
    def task(self):
        try:
            yield self.get()
        finally:
            self.task_done()

你会像这样使用这个版本:

with myqueue.task() as next_task:
    doStuff(next_task)

也可以让task__exit__方法进行一些异常处理,尽管两者之间在如何处理方面存在一些差异。

答案 1 :(得分:1)

有几个简单的选项可以确保在队列中调用task_done(),无论如何。如果您需要对队列中的项目执行的工作很复杂,或者每个项目都有多个代码路径,这些特别有用。

第一个选项特定于队列。它与Rob建议的类似,但它不需要创建Queue的子类。

@contextlib.contextmanager
def mark_done(queue):
    try:
        yield queue.get()
    finally:
        queue.task_done()

queue = Queue()
# assume you put stuff in the queue
with mark_done(queue) as item:
    item.do_stuff()

我喜欢一种更通用的形式,无论什么时候你想在代码块的末尾调用一个函数,它都很有用,而且该函数与块顶部的一个对象有关:

@contextlib.contextmanager
def defer(func):
    try:
        yield
    finally:
        func()

queue = Queue()
# assume you put stuff in the queue
item = queue.get()
with defer(queue.task_done):
    item.do_stuff()

使用第二种形式需要一行额外的代码,但考虑到可读性,它可以非常清楚上下文管理器将要做什么。