2009-04-15 91 views
46

my_var可以是無時使用以下格式是不好的做法嗎?在if語句中依賴條件評估順序安全嗎?

if my_var and 'something' in my_var: 
    #do something 

的問題是,'something' in my_var將拋出一個TypeError如果my_var是無。

或者我應該使用:

if my_var: 
    if 'something' in my_var: 
     #do something 

try: 
    if 'something' in my_var: 
     #do something 
except TypeError: 
    pass 

重新表述的問題,它的上面是Python中的最佳實踐(如果有的話)?

替代品是歡迎的!

回答

64

根據條件的順序(Python reference here)安全可靠,特別是因爲您指出的問題 - 能夠短路評估可能會導致一系列條件中的問題,這是非常有用的。

這種代碼在大多數語言彈出:

IF exists(variable) AND variable.doSomething() 
    THEN ... 
+2

當我看到第二個代碼時,我假設編碼器不理解短路評估的工作原理。 – Dana 2009-04-15 16:04:14

+1

-1:文檔中沒有引用:http://docs.python.org/library/stdtypes.html#boolean-operations-and-or-not – 2009-04-15 17:02:31

+0

@cfi:因爲我可以在答案更改後更改我的投票,我不清楚問題在哪。 – 2011-11-22 19:12:16

1

這是完全安全的,我做這一切的時候。

1

我會去嘗試/除了,但它取決於你所瞭解的變量。

如果您希望變量會在大多數情況下存在,那麼嘗試/除了少一些操作。如果你期望變量在大多數情況下都是None,那麼IF語句將會減少操作。

27

是的,它是安全的,它是明確和很清楚的語言參考定義:

表達x and y首先評估 x;如果xfalse,則返回其值 ;否則,y評估爲 並返回結果值。

表達式x or y首先評估 x;如果x爲真,則返回值爲 ;否則,y評估爲 並返回結果值。

1

並非如此簡單。作爲一個C#的傢伙,我很習慣做這樣的事情:

if(x != null && ! string.isnullorempty(x.Name)) 
{ 
    //do something 
} 

以上的偉大工程,如預期的那樣進行評估。但是,在VB.Net中,以下內容會產生您不期待的結果:

If Not x Is Nothing **And** Not String.IsNullOrEmpty(x.Name) Then 

    'do something 

End If 

上面將生成一個異常。正確的語法應該是

If Not x Is Nothing **AndAlso** Not String.IsNullOrEmpty(x.Name) Then 

    'do something 

End If 

請注意非常微妙的區別。這讓我感到困惑了大約10分鐘(太長),這就是爲什麼C#(和其他人)在使用其他語言進行編碼時需要非常小心的原因。

2

我可能是有點迂腐在這裏,但我要說的是最好的答案是

if my_var is not None and 'something' in my_var: 
    #do something 

的區別在於爲None明確的檢查,而不是my_varTrueFalse的隱式轉換。

雖然我敢肯定,你的情況的區別並不重要,在更普遍的情況下,這將是非常可能的變量不是None,但仍計算爲False,例如0整數值或一個空的列表。

所以與大多數其他海報聲稱它是安全的相反,我會說,只要你是明確的,它就是安全的。如果你不相信再考慮這很做作類:

class Contrived(object): 
    def __contains__(self, s): 
     return True 
    def __nonzero__(self): 
     return False 

my_var = Contrived() 
if 'something' in my_var: 
    print "Yes the condition is true" 
if my_var and 'something' in my_var: 
    print "But this statement won't get reached." 
if my_var is not None and 'something' in my_var: 
    print "Whereas this one will." 

是的,我知道這不是一個現實的例子,但變化都實時發生的代碼,尤其是當None用於表示默認的函數參數。