2013-07-08 49 views
4

我想知道我在做什麼是一個合適的斷言方法。我正在努力使Python的風格指南既簡潔又非常正確。Python斷言風格

try: 
    assert self.port_number == 0 
    assert self.handle == None 
    assert isinstance(port_number, int) or isinstance(port_number, float) 
    assert port_number > 0 
except AssertionError: 
    return -1 

*body of code* 

return 0 

以上是我的代碼的摘錄,顯示我是如何處理的說法斷言。你可以假設我已經涵蓋了所有必要的斷言,輸入是port_number。這被認爲是很好的風格?有沒有更好的辦法?

+0

如果此代碼是一個函數的主體,我會編輯它以顯示它。 –

回答

2

如果調用函數預期的0成功-1失敗輸入,我會寫:

def prepare_for_connection(*args, **kwargs): 
    if (self.handle is not None): 
     return -1 
    if not (isinstance(port_number, int) or isinstance(port_number, float)): 
     return -1 
    if port_number < 0: 
     return -1 

    # function body 

    return 0 

調用非異常行爲太拋出和捕獲的斷言錯誤的機制很多開銷。對於聲明總是爲真的情況,斷言更好,但如果它不是由於某個錯誤導致的,那麼您在該位置會大聲地產生錯誤,或者最好在該位置處理錯誤(使用默認值)。如果您願意,您可以將multiple-if條件組合成一個巨大的條件語句;我個人認爲這更可讀。此外,python風格將使用isis not而不是==!=None進行比較。

一旦程序離開調試階段,Python應該能夠優化斷開斷言。見http://wiki.python.org/moin/UsingAssertionsEffectively

從函數返回錯誤號(-1/0)的C風格約定並不特別pythonic。我會用False0替換-1True,並給它一個語義上有意義的名稱;例如,將其稱爲connection_prepared = prepare_for_connection(*args,**kwargs),因此connection_prepared將是TrueFalse,並且代碼將是非常可讀的。

connection_prepared = prepare_for_connection(*args,**kwargs) 
if connection_prepared: 
    do_something() 
else: 
    do_something_else() 
3

我更喜歡不捕捉函數內的斷言,而是確保調用者處理任何錯誤。這也允許調用者檢查任何未處理的錯誤並檢查回溯以確切地查看錯誤。

您還可以向斷言語句添加錯誤消息。

assert x > 0, "x must be greater than 0" 
1
return -1 

Python有比C的錯誤處理的不同方法如果存在與所提供的數據的問題,只是通過讓AssertionError通,或提出一個TypeErrorValueError與自定義錯誤消息。與斷言語句自定義錯誤消息是最簡單的:

assert port_number > 0, "Invalid port number" 

即斷言語句可以在編譯時被禁用可能是有原因的,如果你想使用斷言在您的情況語句重新考慮這一事實。通常的做法是不使用assert語句來驗證函數用戶的輸入,並且僅用於內部健全性檢查。另一方面,健康檢查和驗證之間的界限並不明確。爲您的代碼的部件,可以不斷言語句:

if port_number <= 0: 
    raise ValueError('Invalid port number') 
if not isinstance(port_number, (int, float)): 
    raise TypeError('Port number must be some kind of number') 

我個人使用斷言來驗證數據,如果無效,將導致崩潰反正遲早聲明(見「鴨打字」)。我還在開發過程中大量使用assert語句,以便像靜態類型語言一樣對數據進行清理檢查。如果我強烈懷疑我自己的代碼的穩定性和可靠性,我只會使用這些斷言。

下一行:

assert self.handle == None 

如果我記錯,PEP8說,你應該寫assert self.handle is None。至少它是由比我聰明的人所認可的。

assert isinstance(port_number, int) or isinstance(port_number, float) 

如果你真的需要這個,它可以寫成isinstance(port_number, (int, float))。但事實證明,你沒有。你不應該在乎是否有人傳遞了一個數字原始類型或一些自制的類來重載所有的比較運算符。

也許有一兩件事你可以做的是儘量端口轉換爲整數,看它是否可用與否:

try: 
    port_number = int(port_number) 
except ValueError: 
    raise ValueError("Invalid port number") 

,並且在這種情況下,你可以只通過,則讓ValueError通消息對新手來說不會有什麼信息。

5

assert語句應該只用於檢查程序的內部邏輯,從不檢查用戶輸入或環境。從最後兩段在http://wiki.python.org/moin/UsingAssertionsEffectively報價...

斷言應該被用來測試可以 因爲惡意的用戶輸入或操作系統/環境 故障,如文件的出現故障的情況下未被發現。相反,您應該引發一個異常,或者打印一條錯誤消息或其他適當的東西。一個 爲什麼斷言只能用於 的自檢的一個重要原因是該程序可以在編譯時禁用斷言。

如果Python是使用-O選項啓動的,則斷言將被剝離並且不被評估。因此,如果代碼嚴重使用斷言, 但對性能至關重要,那麼有一個系統可以在發佈版本中將它們關閉 。在(但不這樣做,除非真的有必要 。它被科學證明,一些錯誤只顯示 當客戶使用的機器,我們希望斷言,以幫助那裏 了。)

有了這個因爲斷言失敗的全部要點是儘快通知程序員,程序中存在邏輯錯誤,所以在用戶代碼中幾乎沒有任何理由要捕獲斷言。