2012-09-05 110 views
18

這是我在Django項目中發生的一個問題。這是關於表單驗證。Python:避免短路評估

在Django中,當你有一個提交的表單時,你可以在相應的表單對象上調用is_valid()來觸發驗證並返回一個布爾值。所以,平時你有這樣的代碼裏面視圖功能:

​​3210

is_valid()不僅驗證表單數據,而且還增加了錯誤消息,可以事後向用戶顯示錶單對象。

在一個頁面上,我一起使用了兩個表單,並且還希望僅當兩個表單都包含有效數據時才保存數據。這意味着我必須在執行代碼保存數據之前在兩個窗體上調用is_valid()。最明顯的方法是:

if form1.is_valid() and form2.is_valid(): 
    # ... 

由於邏輯運算符的短路評估而不起作用。如果form1無效,form2將不會被評估,並且其錯誤消息將會丟失。

這只是一個例子。據我所知,與其他語言(即Smalltalk)相比,and/or沒有貪婪的替代選擇。我可以想象在不同情況下發生的問題(不僅在Python中)。我能想到的解決方案都是笨拙的(嵌套ifs,將返回值分配給局部變量並在if語句中使用它們)。我想知道解決這類問題的pythonic方法。

在此先感謝!

回答

27

如何類似:

if all([form1.is_valid(), form2.is_valid()]): 
    ... 

在一般的情況下,可以使用一個列表的理解,因此結果被預先計算(而不是其通常在該上下文中使用的發電機的表達) 。例如: -

if all([ form.is_valid() for form in (form1,form2) ]) 

這將很好地擴展到條件任意數量,以及...,唯一的缺點是,它們都需要通過「and」連接,而不是if foo and bar or baz: ...

(對於非短路or,您可以使用any而不是all)。

+0

正是我所期待的。謝謝! – j0ker

+2

這花了我幾秒鐘的時間。這是我之前沒有考慮過的一個角落案例(我經常在Fortran工作,但不能保證短路,但允許它),而且我總是試圖弄清楚如何確保我的表達式被短路。搞清楚這一點對我來說有點倒退:)。 – mgilson

+0

是的'全部'是去這裏的路,但你在哪裏使用列表解析?我只看到一個簡單的例子。 – rantanplan

16

您可以簡單地使用二元運算符&,它將在bools上執行非短路邏輯

if form1.is_valid() & form2.is_valid(): 
    ... 
+3

更具體地說,它會對整數進行按位「和」操作。由於bools碰巧是從具有「True == 1」和「False == 0」的整數派生的,所以這可以起作用。它不會(必然)適用於其他類型或返回非布爾值的函數。儘管如此,這是一個很好的工具(+1) – mgilson

+1

絕對比mgilson的解決方案簡單。感謝那!另一個可能對閱讀代碼的其他人更有幫助。在這裏,我想你可能會認爲我只是混淆了'和'和'&'。 – j0ker

+0

@mgilson全功能也是第一個進入我腦海的解決方案(我將它用於j0ker提到的原因),但我發現問題遲到了(+1,btw):-) – sloth