2013-10-18 21 views
2

有沒有在with語句中使用Python Queue的標準方法?這是我想能夠使用它:使用帶有「with」語句的Python隊列

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

有用於Queue對象沒有__enter____exit__方法,所以這是行不通的。有沒有任何語法糖讓它看起來比這更好?

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

編輯:我有兩個原因,希望在這種情況下,使用with聲明。首先,我認爲with聲明可以幫助我的代碼變得更清晰一些,特別是當不止doStuff的單個調用時。其次,如果有一些簡單的東西,我可以養成習慣於每次使用的習慣,這樣可以確保我永遠不會忘記致電task_done,或者遇到錯誤可能導致呼叫被跳過的情況,這將是件好事。

+5

我認爲你擁有的是完美的。花你的時間擔心更大的問題。 :) – arshajii

+1

帶'__enter__'和'__exit__'方法的子類隊列?但我真的不認爲這很重要。 – rlms

+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__方法做了一些異常處理,但也有在怎麼說兩者之間的一些差異完成。

0

有幾個簡單的選項可以確保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() 

使用這個第二種形式需要額外的一行代碼,但考慮到可讀性,它很清楚上下文管理器將要做什麼。