2011-09-06 22 views
7

我有很多函數從文件中解析數據,通常返回結果列表。我想返回一個值並引發異常,這是否意味着我做錯了什麼?

如果我在文件中遇到了一條狡猾的線,我想讓士兵處理有效線並返回它們。但我也想把錯誤報告給調用函數。我想報告它的原因是,調用函數可以通知用戶文件需要查看。我不想在解析函數中開始使用GUI,因爲這似乎是對關注點分離的嚴重違反。解析函數無法訪問控制檯我正在寫錯誤消息。

這讓我想要返回成功的數據,但也因爲錯誤而引發異常,這顯然是我做不到的。

考慮以下代碼:

try: 
    parseResult = parse(myFile) 
except MyErrorClass, e: 
    HandleErrorsSomehow(str(e)) 

def parse(file): #file is a list of lines from an actual file 
    err = False 
    result = [] 

    for lines in file: 
     processedLine = Process(line) 
     if not processedLine: 
      err = True 
     else 
      result.append(processedLine) 
    return result 
    if err: 
     raise MyErrorClass("Something went wrong") 

顯然,最後三行是沒有意義的,但我不能想出一個好的辦法做到這一點。我想我可以做return (err, result),並調用它像

parseErr, parseResult = parse(file) 
if parseErr: 
    HandleErrorsSomehow() 

但返回錯誤代碼似乎很取消Python的,更不用說返回的錯誤代碼和實績值的元組。

事實上,我覺得我想在應用程序中做一些如此奇怪的事情,這應該不會非常複雜,這讓我覺得我可能做錯了什麼。有沒有更好的解決這個問題?或者有什麼方法可以使用finally來同時返回一個值並引發異常?

+0

在這種情況下,如果沒有錯誤發生,我可能會返回一個元組'processedData,errorInformation',並且'errorInformation'是一個空字符串。另一個選擇是使用一個回調函數,如果發生錯誤時調用一些錯誤信息 - 如果調用者不關心,它可以傳遞'None'作爲回調。 –

回答

7

沒有人說只有對待「錯誤」的有效方法是引發異常。調用者需要兩條信息:(1)有效數據,(2)是否發生錯誤(可能是出錯的地方,因此可以格式化有用的錯誤消息)。這是返回一對值的完全有效和地上的情況。

另一種設計是通過一個可變集合給函數作爲參數,讓它填補它要發射到的任何錯誤消息。這通常會簡化調用程序中的管道,特別是如果解析器和代碼之間存在多個層次的調用,而這些層次之間會知道如何處理錯誤消息。

+0

您最後一句話 - 這是我尋找更好的方式來做到這一點的主要原因之一。沒有想過使用'out參數'。 (他們是否有更好的名字?) –

+0

儘管在理想的世界中發出警告可能更加優雅,但Jython僅達到2.5的事實使我對此不切實際。我最終傳遞了一個由解析函數填充的列表。在我連續調用幾個不同的解析函數的地方,這種方法特別有效,然後我可以在完成所有警告列表後迭代整個警告列表。我喜歡這個比返回元組和檢查單獨的返回值多得多。 –

+1

@CamJackson對於這樣的情況。我經常發現,使用指定的呼叫簽名傳遞迴調比傳遞原始列表更好。這樣一來,將實現從內部抽象出來很容易,並且在調用者不關心錯誤返回的情況下放置一個存根回調。通常,它可以像傳入要添加的列表的綁定的'.append'方法一樣簡單。它更清楚地表明某些東西正在傳回(「out」參數並不總是顯而易見),並允許調用者在出錯時進行復雜的處理。 –

4

Emit a warning而是讓代碼決定如何處理它。

+0

這很可愛。不知道這個模塊是否存在。它看起來像警告可以連接到python的日誌記錄,這可以反過來連接到gui。 –

+0

這看起來很有希望,現在看着這個。唯一的是,我使用Jython,它似乎沒有'warnings.catch_warnings()',所以我不知道我是如何處理警告的。我可以試着把它們看成是一個異常嗎? –

+0

嗯,我通讀[this](http://www.jython.org/jythonbook/en/1.0/ExceptionHandlingDebug.html#issuing-warnings),但它並沒有說如何調用函數可以捕獲警告。除非我使用過濾器將警告轉化爲例外,但是我回到我開始的地方不是我嗎?你知道如何處理警告,而不使用'catch_warnings()'? –

0

我來自.NET世界,所以不知道如何轉換成Python ...

在像你這樣的情況下,(要處理在單個調用衆多的物品),我會返回一個MyProcessingResults例如:

  • MyProcessingResults.ProcessedLines - 保存您解析的所有有效數據。
  • MyProcessingResults.Errors - 包含所有錯誤(假設您有多個錯誤,並且您想明確知道所有錯誤)。
+2

這樣的聲音就好像剛剛返回結果的元組和任何錯誤。在python中,一個元組可以容納不同類型的對象,所以不需要定義一個包含我想要傳回的2個對象的類,如果這是我想要做的。 –

1

另一種可能的設計是通過將錯誤處理程序作爲參數傳遞來反轉控制。

(另外,不要覺得你必須告訴Python的列表中積累的數據。它已經知道了,這不是很難在這裏做一個列表理解的工作。)

def sample_handler(): 
    print "OMG, I wasn't expecting that; oh well." 

parseResult = parse(myFile, sample_handler) 

def parse(file, handler): #file is a list of lines from an actual file 
    result = [Process(line) for line in data] 
    if not all(result): handler() # i.e. if there are any false-ish values 
    result = filter(None, result) # remove false-ish values if any 
    return result 
+0

我的數據文件的格式比我想象的要複雜一點,所以實際上我不得不手動迭代列表,但這是一個很酷的方法。 Python充滿了令人驚喜的驚喜! –

1

根據來電者設計。使用回調可能是合理的:

def got_line(line): 
    print 'Got valid line', line 

def got_error(error): 
    print 'got error', error 

def parse(file, line, error): 
    for lines in file: 
     processedLine = Process(line) 
     if not processedLine: 
      error(MyErrorClass("Something went wrong")) 
     else 
      line(processedLine) 


parse(some_file, got_line, got_error) 
1

我想提出一種替代解決方案;使用一個類。

class MyParser(object): 
    def __init__(self): 
     self.warnings = [] 

    def parse(self, file): 
     ... 

現在解析功能,可以設定警告的warnings列表,用戶可以檢查這個名單,如果他們願意的話。

只要我的功能開始變得比「處理這個並返回我的價值」更先進,我喜歡考慮使用類。它將相關代碼集中到一個對象中,並且與返回信息元組的函數相比,它使得代碼更簡潔,用法更簡單。

相關問題