在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
或有一个错误可能导致调用的情况被跳过。
答案 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()
使用第二种形式需要一行额外的代码,但考虑到可读性,它可以非常清楚上下文管理器将要做什么。