2014-04-29 99 views
3

以下是否有區別?Python 3 and-or vs if-else

print(x if x else 'no x available') 
# compared to: 
print(x and x or 'no x available') 
+3

區別在於第一個是可讀的。 –

+0

/我正在等待某人使用[dis](https://docs.python.org/2/library/dis.html#module-dis)。 – luk32

+2

等待,你忘了'['no x available',x] [bool(x)]'* ducks * – kojiro

回答

2

實際上它們是相同的;在理論上它們是不同的,但只有當__bool__方法都有副作用:

>>> class Weird: 
    state = False 
    def __bool__(self): 
     self.state = not self.state 
     return self.state 


>>> x = Weird(); print(x if x else 'no x available') 
<__main__.Weird object at 0x0000000003513160> 
>>> x = Weird(); print(x and x or 'no x available') 
no x available 

如果碰上你有更嚴重的問題擔心這個理論情況。

還要注意的是:

>>> x = Weird(); print(x or 'no x available') 
<__main__.Weird object at 0x00000000035071D0> 

所以克拉斯伊萬的​​答案是技術上的錯誤。

底線,使用if表達式,因爲它可以更清楚地表達您的意思。

+0

這是我所希望的那種答案;他們如何行動的實際差異(我知道,我應該更清楚地詢問一下)。儘管謝謝你的回答! :) –

+0

是啊!剛剛意識到這一點並回過頭來進行編輯,而且您已經證明了我想要添加的東西 - 唯一的區別是'__bool __(self)'方法不是「純函數」。 –

+0

@KlassIvan我編輯了我的答案,使這一點更清晰。 – Duncan

7

兩條線都相同:

print(x or 'no x available') 

關於第二替代: 始終牢記的是,根據操作者的優先級and首先計算,所以它首先計算x and x,這是完全無用的 - 它等於x

+0

ideone的python將你的代碼編譯成不同於OP版本的字節代碼co我不確定是否可以說他們是一樣的。 – luk32

+0

請問您可以編譯'return x and x and x and x and x' and'return x'(毫無疑問,它們是相同的)。他們會在字節碼中有所不同嗎? –

+1

http://ideone.com/e7LFCy好像默認的python解釋器不會執行很多優化。 – luk32

2

運行此:

import dis 
def f1(): 
    print(x if x else 'no x available') 
def f2(): 
    print(x and x or 'no x available') 
def f3(): 
    print(x or 'no x available') 
dis.dis(f1) 
dis.dis(f2) 
dis.dis(f3) 

我們得到,對於f1

4   0 LOAD_GLOBAL    0 (x) 
       3 POP_JUMP_IF_FALSE  12 
       6 LOAD_GLOBAL    0 (x) 
       9 JUMP_FORWARD    3 (to 15) 
     >> 12 LOAD_CONST    1 ('no x available') 
     >> 15 PRINT_ITEM   
      16 PRINT_NEWLINE  
      17 LOAD_CONST    0 (None) 
      20 RETURN_VALUE   

f2

7   0 LOAD_GLOBAL    0 (x) 
       3 POP_JUMP_IF_FALSE  12 
       6 LOAD_GLOBAL    0 (x) 
       9 JUMP_IF_TRUE_OR_POP  15 
     >> 12 LOAD_CONST    1 ('no x available') 
     >> 15 PRINT_ITEM   
      16 PRINT_NEWLINE  
      17 LOAD_CONST    0 (None) 
      20 RETURN_VALUE   

對於來自@Klass伊萬採取f3

10   0 LOAD_GLOBAL    0 (x) 
       3 JUMP_IF_TRUE_OR_POP  9 
       6 LOAD_CONST    1 ('no x available') 
     >> 9 PRINT_ITEM   
      10 PRINT_NEWLINE  
      11 LOAD_CONST    0 (None) 
      14 RETURN_VALUE   

所以f1f2是不一樣的。正如克拉斯提到的,他們有不同的邏輯。 f3f1版本也有所不同,即使邏輯上它們應該相當,f3備用一些操作。

+0

準確 - '9 JUMP_FORWARD'與'9 JUMP_IF_TRUE_OR_POP' - f1和f2不一樣。 –

+0

@KlassIvan我注意到它並編輯它。不過,謝謝你指出。 – luk32

0

代碼方面,我認爲這已被涵蓋,但我會注意到,你在這裏做的是在語言上非常不同,並且可能對讀取你的代碼的人有非常不同的影響,也許只是那些潛意識瀏覽網站的前端(即使是通過參與或瞭解代碼的人也會發現自己在心理上受到潛在'符號鏈接'的影響*)。要進一步打破下來,讓我們考慮一個字符串值x

var x = "spoon"; 
print(x if x else 'no x available') 
# compared to: 
print(x and x or 'no x available') 

它仍然很難看到究竟會發生什麼,「勺子」在這裏,所以讓事情更清晰,我們可以只需撥打我們的變量「hasSpoon」而不是給它分配一個字符串(但是如果你喜歡的話,你可以相信我們已經給它分配了一串「勺子」......):

print(hasSpoon if hasSpoon is true else 'no hasSpoon available') 
# compared to: 
print(hasSpoon and hasSpoon or 'no hasSpoon available') 

正如我們所看到的,在一審的邏輯閱讀將是我們的隱喻餐具的持有者有一個勺子,如果他們有一個勺子,我想我們會在(和其他可能同意他們有沒有提供給他們的勺子的條件,而不是實際上有一個有點奇怪,但可能的勺子,但現在讓我們暫時擱置它。)

在第二個表達式中,邏輯蘊涵相反,我們的理論小餐館裏有一把勺子,還有一把勺子,這是一種重複的方式。因此,如果您想向任何潛在的代碼讀者以及任何可能受其代理人影響的人表達意見,那些有勺子的人很可能會有勺子,而那些沒有選擇沒有勺子,你會使用第一個選項。另一方面,如果你想表示某個人既有勺子又有勺子,或者他們有沒有向他們開放勺子的條件,你可以使用第二個表達式。

什麼的。

*我在這裏象徵性地使用術語,如果你會赦免雙關語。