2013-11-20 33 views
6

我正在使用基於Python的API,其中有很多功能來查詢事件,如doesPointExist,findPoint,canCreateNewPoint等,其中否定結果引發異常。這使代碼更加混亂,充滿了try/catch語句,而不是直接使用結果作爲布爾值。在設計Python API時,拋出異常還是返回false/None等是Pythonic?

由於我不是Python專家,我想知道這個設計是否是Pythonic?儘管我在標準庫中沒有看到這種設計,但我認爲Python API中的這種異常用法令人不悅?

+0

使用異常而不是檢查返回碼通常更加pythonic。 [EAFP](http://docs.python.org/2/glossary.html#term-eafp) – Tim

回答

6

API設計是一門藝術。函數的名稱應該表明它的行爲方式,包括設置用戶的期望值。名爲findPoint的函數意味着搜索可能失敗,因此沒有這樣的點存在的情況並不例外,並且可以返回None來表示結果。然而,一個名爲getPoint的函數會暗示我可以始終返回請求的點。失敗將是意想不到的,並且有理由引發例外。

+1

完全與你在前兩句話。這兩個句子是Simeon Visser的答案中真正缺少的。不幸的是,我不認爲你選擇了最好的例子。 'getPoint'特別提醒'dict.get',它的唯一目的是確保你不會遇到異常。這就是說,我明白你要用那個例子去哪裏。對我而言,'get'本質上更加模糊。我會專注於扣籃的情況:'doPointExist'顯然不應該因爲點不存在而加註!該函數的名稱是一個問題!你想要一個答案。答案可能不是。 –

+0

由於Simeon Visser很好地覆蓋了這方面,所以我沒有討論'doesPointExist'。我其實是希望這個答案更多地是他的答案的擴展,因爲這太長了評論。 – chepner

6

聽起來就像設計糟糕的API。

  • 功能doesPointExist應該返回TrueFalse,當點不存在,它不應該拋出異常。
  • 函數findPoint應該返回一個Point對象或None當沒有找到對象時。
  • 出於類似原因,函數canCreateNewPoint應該返回TrueFalse

例外情況是例外情況。

3

我不同意你不會在標準庫中找到它。例如,"abc".index("d")增加了ValueError,很多圖書館自由地提出例外。

我想說這取決於失敗行爲的後果是什麼。

  • 如果主叫方可以不改變返回值的工作,我會返回一個空值(或False,如果它是一個yes或no的問題)。
  • 如果調用失敗,我會引發異常。例如findPoint()可能會這樣做,如果它通常返回調用者想要處理的對象Point
2

1,我會建議在非常特殊的情況下使用異常,所以你不需要在常見情況下測試它們。

2,您應該閱讀關於您的函數名稱的指南PEP8 Naming Conventions

2

這不是Python獨有的。其他答案是好的,但只是沒有很好地成爲評論一些額外的想法:

  • 你使用異常,當你不希望(或需要)來檢查結果。在這種模式下,您只需執行該操作,並且如果某處出現錯誤,則會拋出異常。擺脫顯式檢查可以縮短代碼時間,並且在發生異常時仍然可以獲得良好的調試信息,因此很常見。這是EAFP(比請求更容易要求寬恕)的風格。
  • 當您想要檢查結果時使用返回碼。如果故障不會總是乾淨地失敗,或者有助於在複雜的代碼流中進行調試,則有時需要顯式檢查。這有時被稱爲LBYL(看你跳躍之前)的風格。

在Python中,最喜歡的解釋性語言,因爲開銷是如此之高,例外情況是相對便宜,所以它更常見於Python中使用EAFP比,也就是說,C++,其中開銷較低,例外的是(相對)更貴。

請注意,函數可能會給出返回值可能會引發異常。

在您的示例中,像doesPointExist這樣的函數意味着用戶實際上想在嘗試某些操作之前驗證訪問權限。這是LBYL。作爲結果值拋出一個異常是EAFP編程風格的一部分,並且對於這個函數沒有任何意義 - 如果你想要這種風格,你不會檢查,你只會這樣做,並在點不存在。

然而,即使在這裏有假設 - 你已經給出了一個有效的觀點。如果該函數返回True/False是否存在該點,那麼將會很好,如果某個不是點的東西被傳遞給它,則會拋出異常。