2011-10-31 35 views
13

爲了消除潛在的競爭條件,我編寫了一個python模塊來監控一些專門的工作流程,我學習了python的「比權限更容易請求原諒」(EAFP)編碼風格,現在我提高了大量的自定義異常嘗試/除了我曾經使用如果/ thens的塊。應該在python中定義自定義異常的頻率如何?

我是python的新手,這種EAFP風格在邏輯上有意義,似乎使我的代碼更健壯,但有些事情感覺過度。每種方法定義一個或多個例外是不好的做法?

這些自定義異常往往只對單一方法有用,雖然它感覺像一個功能正確的解決方案,但它似乎有很多代碼需要維護。

這裏有個例子的樣品的方法:

class UploadTimeoutFileMissing(Exception): 
    def __init__(self, value): 
     self.parameter = value 
    def __str__(self): 
     return repr(self.parameter) 

class UploadTimeoutTooSlow(Exception): 
    def __init__(self, value): 
     self.parameter = value 
    def __str__(self): 
     return repr(self.parameter) 

def check_upload(file, timeout_seconds, max_age_seconds, min_age_seconds): 

    timeout = time.time() + timeout_seconds 

    ## Check until file found or timeout 
    while (time.time() < timeout): 

     time.sleep(5) 
     try: 
      filetime = os.path.getmtime(file) 
      filesize = os.path.getsize(file) 
     except OSError: 
      print "File not found %s" % file 
      continue 

     fileage = time.time() - filetime 

     ## Make sure file isn't pre-existing 
     if fileage > max_age_seconds: 
      print "File too old %s" % file 
      continue 

     ## Make sure file isn't still uploading 
     elif fileage <= min_age_seconds: 
      print "File too new %s" % file 
      continue 

     return(filetime, filesize) 

    ## Timeout 
    try: 
     filetime 
     filesize 
     raise UploadTimeoutTooSlow("File still uploading") 

    except NameError: 
     raise UploadTimeoutFileMissing("File not sent") 
+1

Python標準庫有大約200k行代碼,並有165個例外 - 確定您需要自己的代碼? (我從一個叫做「[停止寫作課程](http://youtu.be/o9pEzgHorH0)」)的談話中拉出數字 – Glider

回答

5

定義每個方法

一個或多個例外。如果你的意思是異常每方法實際上定義爲「方法體中」,然後。這是不好的做法。如果你定義了兩個與同一個錯誤相關的異常,但是你創建了兩個異常,因爲兩個不同的方法引發它們,這也是正確的。

如果你問它是否是不好的做法,提高超過每方法只有一個例外,那沒有,這是很好的做法。如果這些錯誤不屬於同一類別,那麼可以爲每個模塊定義幾個例外。

一般來說,較大的模塊將定義多個異常。如果你在一些算術庫上工作,你會定義一個ZeroDivisionError和一個OverflowError(如果它們還沒有在python中定義,因爲你當然可以重用這些),那很好。

+0

他可能意味着與方法計數相關的例外數量(計數)。即。 3個方法=> 4個例外,8個方法=> 11個例外 – n611x007

3

是不好的做法來定義每個方法的一個或多個異常?

是的。

每個模塊一個更典型。它當然取決於詳細的語義。這個問題歸結爲:「你會試圖抓住什麼?」

如果你永遠不會在你的代碼中使用except ThisVeryDetailedException:,那麼你非常詳細的異常並不是很有幫助。

如果你能做到這一點:except Error as e: if e.some_special_case它事項很少的時間,那麼你可以很容易地簡化爲每個模塊一個異常,並處理您的特殊情況爲例外的屬性,而不是不同類型的異常。

常見建議(每個模塊一個,名稱爲Error)意味着您的代碼通常看起來像這樣。

try: 
    something 
except some_module.Error as e: 
    carry on 

這給你一個很好的命名約定:module.Error。這涵蓋了許多罪過。


在一個不相關的音符,如果你認爲你有「潛在的競爭條件」你應該正確地重新設計的東西或停止嘗試使用線程或切換到多。如果你使用多處理,你會發現避免競爭條件非常容易。

0

我不認爲有必要對每種可能的情況都有一個非常特殊的例外情況。一個UploadTimeoutError可能會很好,你可以自定義異常字符串 - 畢竟這是字符串的用途。請注意,Python對於每種可能類型的語法錯誤都沒有單獨的例外,只是一般的SyntaxError

此外 - 是否真的有必要爲每個自定義異常定義__init____str__方法?據我所知,如果你不打算使用任何不尋常的行爲,你不需要添加任何代碼:

>>> class MyException(Exception): pass 
... 
>>> raise MyException("oops!") 
Traceback (most recent call last): 
    File "<ipython console>", line 1, in <module> 
MyException: oops!  
>>> str(MyException("oops!")) 
'oops!' 
3

我要在權衡這一點,因爲自定義異常是親愛的我心。我會解釋我的情況,讀者可以衡量他們自己的情況。

我是一個視覺特效公司的管道架構師 - 我所做的大部分工作都涉及開發我稱之爲「Facility API」的工具 - 它是一個處理所有事情的系統,包括在文件系統中定位事物,管理模塊/工具/項目配置,以處理來自各種CG應用程序的數據類型以實現協作。

我竭盡全力,試圖確保Python的內置異常從來沒有泡沫了。由於我們的開發人員將依賴現有模塊的生態系統來構建自己的工具,因此使得通用的IOError轉義是適得其反的 - 特別是因爲調用例程甚至可能不知道它正在讀取文件系統(抽象是一件美麗的東西)。如果底層模塊無法表達對該錯誤有意義的內容,則需要做更多的工作。

我來解決這樣的做法是創建一個從所有其他設施異常派生的設施異常類。對於特定類型的任務或特定的主機應用程序,有子類可以讓我自定義錯誤處理(例如,Maya中引發的異常將啓動UI以幫助排除故障,因爲通常的異常會在不顯眼的控制檯中引發並且通常會被忽略)。

報告的種種內置於設備異常類 - 例外似乎沒有給用戶而不也正在內部報告。對於一系列例外情況,我會在任何時候提出即時消息。其他人只是悄悄地報告一個數據庫,我可以查詢最近(每日或每週)的報告。每個鏈接到從用戶會話捕獲的EXTENSIVE數據 - 通常包括屏幕截圖,堆棧跟蹤,系統配置以及更多。這意味着我可以在報告問題之前有效地對問題進行排查 - 並且比大多數用戶可能提供的信息更多。

的目的非常精細的灰階氣餒 - 例外接受傳遞的值(有時甚至是一本字典,而不是一個字符串,如果我們要提供大量用於故障排除的數據),提供與他們的格式化輸出。

因此,沒有 - 我不認爲定義異常或兩個每個模塊是不合理的 - 但它們必須是有意義的,並添加了一些項目。如果您只是將IOError換成raise MyIOError("I got an IO error!"),那麼您可能需要重新考慮這一點。