5

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

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

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

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

编辑:在这种情况下,我有两个想要使用with语句的原因。首先,我认为with语句会帮助我的代码更简洁一些,尤其是当不止一次调用doStuff. 其次,最好有一些简单的东西,我可以养成每次使用的习惯,以确保我永远不会忘记调用task_done或遇到错误可能导致调用被跳过的情况。

4

2 回答 2

3

有几个简单的选项可以确保 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()

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

于 2016-07-27T22:49:59.260 回答
2

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

然而,正如 sweeneyrod 所提到的,可以继承 Queue 和 add__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)

也可以让taskand__exit__方法进行一些异常处理,尽管两者在处理方式上存在一些差异。

于 2013-10-18T19:01:55.090 回答