2011-01-19 86 views
1

我不確定我的問題有一個具體的答案,但無論如何。我正在編寫一個有很多參數的函數,每個函數都可以是None或者有一個有限的值範圍。由於我不相信用戶給我很好的輸入,我必須檢查每個參數的類型,如果它的類型正確(或None),那麼我想看看它是否在正確的範圍內。這意味着我有這樣大量的代碼:Python中的邏輯參數檢查

# size 
if isinstance(size, str): 
    if size in range(4): 
     self.data[uid]['size'] = int(size) 
    else: 
     warnings.warn("ID %s: illegal size %s" % (uid, size)) 
     self.data[uid]['size'] = None 
elif size == None:         
    self.data[uid]['size'] = None 
else: 
    warnings.warn("ID %s: illegal size %s" % (uid, str(size))) 
    self.data[uid]['size'] = None 

等。這是成爲重複的,我想知道是否有可能是會自動執行此,拋出異常/警告,並減少代碼冗餘庫。

感謝

+6

`我必須檢查每個參數的類型`聽起來像你做錯了。你應該只用它作爲預期的類型,然後捕捉失敗。 – Falmarri 2011-01-19 22:03:21

+3

我曾經認爲我也必須檢查輸入。當我停止這樣做時,編程變得更加容易。假設沒關係,並處理錯誤。這與python成語「容易要求寬恕而不是權限」有關。 – Wilduck 2011-01-19 22:07:46

回答

1

我想知道是否有可能是一個 庫會自動執行此, 拋出異常/警告,並減少 代碼冗餘。

我使用formencode這樣的東西。它似乎只用於解析HTML表單,但它會高興地解析和驗證您傳遞給它的任何內容。您可以定義一次驗證所有輸入的模式類。

0

如果你的項目是一個庫,你的「用戶」是另一家開發商,不這樣做的。頂多有一個斷言替換你的測試:

assert 0 <= int(size) <= 4, "size must be between 0 and 4" 

這樣,當用戶提供錯誤的輸入,他們會聽到它馬上 - 那麼它變成自己的責任得到它的權利。


如果你的項目是一個應用程序,你的「用戶」是我奶奶,你需要做自己的驗證:撞車出局不是一個可接受的響應。但是,在這種情況下,您應該更多地瞭解可能的輸入(例如,它來自文本框,因此它只能是一個字符串)。

我的建議是編碼你的效用函數,並單獨執行驗證(即UI層)。一個實用程序/庫函數應該驗證並覆蓋(甚至是警告)這個值是非常罕見的:它需要阻止調用者/用戶進一步得到它,直到他們已經把事情做好了。

1

我同意上面的說法:假設size是正確的類型,如果不是,則引發異常(或返回錯誤)。

雖然在處理可能引發異常的輸入時存在一個有用的模式:包裝輸入引發的任何異常,使其包含輸入。例如,所以你會得到:

 
ParseError: while parsing 'number = foo': ValueError: invalid literal for int() with base 10: 'foo' 

的代碼看起來是這樣的:

try: 
    parse(input) 
catch Exception, e: 
    raise ParseError("while parsing %r: %r" %(input, e)), None, sys.exc_info()[2] 

的第三個參數raise將使用原來的追蹤,所以堆棧跟蹤將指向你的實際上導致錯誤的行(例如,size = int(value))而不是對raise的調用。

1

我想改寫這個:

# size 
if isinstance(size, str): 
    if size in range(4): 
     self.data[uid]['size'] = int(size) 
    else: 
     warnings.warn("ID %s: illegal size %s" % (uid, size)) 
     self.data[uid]['size'] = None 
elif size == None:         
    self.data[uid]['size'] = None 
else: 
    warnings.warn("ID %s: illegal size %s" % (uid, str(size))) 
    self.data[uid]['size'] = None 

這樣的:

if size in ["0", "1", "2", "3"]: # alternative: if size in map(str, range(4)): 
    self.data[uid]['size'] = int(size) 
else: 
    if size != None: 
     warnings.warn("ID %s: illegal size %s" % (uid, size)) 
    self.data[uid]['size'] = None  

我真誠地不喜歡的是使用isinstance(size, str)(顯式類型檢查一般是在Python中,因爲它很容易地皺起了眉頭打破ducktyping)。

這就是爲什麼你不容易在Python中找到一個庫來自動化類型檢測的原因:它違背了語言的核心意圖。