2014-03-19 23 views
9

我急於知道的是什麼,例如所有VS和任何VS或

all and "and" 
any and "or" 

之間的區別: 狀態1 = 100,狀態2 = 300,STATUS3 =​​ 400

哪個最好使用:

if status1==100 and status2 ==300 and status3 ==400: 

if all([status1==100,status2==300,status3=400]): 

類似地,對於任何和或病症:

if status1==100 or status2 ==300 or status3==400: 
or 
    if any([status1==100, status2 ==300, status3==400]) 

哪一個是比較有效,使用內置的功能或原始或和與條件?

+2

如果你做'all([status1 == 100,status2 == 300,status3 = 400]),它首先必須創建整個列表,所以我猜'和'是更好的。雖然可能與發電機不同。 –

+1

您可以['timeit'](http://docs.python.org/2/library/timeit.html)確定,但我認爲使用邏輯運算符總是比使用邏輯運算符更快,而不是構建新的列表對象並調用一個函數。 – 2rs2ts

回答

14

關鍵字andor遵循Python的short circuit evaluation規則。由於allany是函數,因此將評估所有參數。如果某些條件是函數調用,可能會得到不同的行爲。

+4

這是一個可靠而簡單的答案,可以說明問題的關鍵。如果你只需要一個'if'語句並且你手頭有變量,那麼使用any/all可能是錯誤的選擇。任何/全部都是用來反對謂詞函數列表的。它們在功能風格的編程中很受歡迎。考慮「如果有的話(數據中x是isOdd(x))''。這裏你有來自某個地方的數據,你想對此做出決定。 –

+2

所有與'any'或'all'有關的參數都會被評估,但是它們的*真值*可能不是,因爲這些函數也是短路的 - 嘗試任何(1/i代表[i]中的[1])。 ' – Air

+0

如果您不想「嘗試」,則上面的計算結果爲True。實際上1/0不被評估,因爲1/1已經是真的。交換1和0的順序,然後中斷。 – Robino

-1

TL;博士

據我所知,all是更好,當你可能會比較布爾語句的變化量,並使用and是多大一有限布爾陳述更好,並採用all時使用,嘗試使用生成器函數。

詳細

編輯解釋(用於使用術語短挑錯推薦打印的清楚) 及其在有限語句使用是優選的,因爲Python將短路每個布爾語句一旦真相的評價可以確定。 請參閱答案的結尾處以獲取證明和詳細示例。

由於由連續and報表的任何聲明將False如果至少有一個說法是False那麼編譯器只知道檢查,直到它到達一個虛假的答案:

status1 == 100 and status2 == 300 and status3 == 400 

它會檢查status1 == 100如果這被發現是False,它會馬上停止處理該陳述,如果它是True如果現在檢查status2 == 300

這種邏輯可以直觀使用循環論證:

圖片我們寫的和聲明的行爲,你會檢查每個語句沿線,並確定是否所有的人都True並返回True或者我們會找到一個False值並返回False。您可以在達到第一個虛假陳述後節省時間,並立即退出。

def and(statements): 
    for statement in statements: 
     if not statement: 
      return False 
    return True 

or我們會寫會盡快爲True語句中找到退出,因爲這證明全部或語句是不相關的報表的總體列真理作爲一個整體邏輯:

def or(statements): 
    for statement in statements: 
     if statement: 
      return True 
    return False 

該邏輯,當然混合並適當地交織在一起服從操作的順序的時andor語句混合在一起

andany聲明有助於避免出現這種情況:

collection_of_numbers = [100,200,300,400,500,600,.....] 
if collection_of_numbers[0] == 100 and collection_of_numbers[1] == 200 and .......: 
    print "All these numbers make up a linear set with slope 100" 
else: 
    print "There was a break in the pattern!!!" 
or

collection_of_numbers = [100,200,300,400,500,600,.....] 
if collection_of_numbers[0] == 100 or collection_of_numbers[1] == 200 or .......: 
    print "One of these numbers was a multiple of 100" 
else: 
    print "None of these numbers were multiples of 100" 

例如

同理:

temp = [] 
itr = 0 
for i in collection_of_numbers: 
    temp.append(i == itr) 
    itr += 100 
if all(temp): 
    print "The numbers in our collection represent a linear set with slope 100" 
else: 
    print "The numbers in out collection do not represent a linear set with slope 100" 

的一種愚蠢的例子,但我認爲這體現了類型當all可能有些用處時。

類似的說法是對任何提出:

temp = [] 
for i in collection_of_numbers: 
    temp.append(i%3 == 0) 
if any(temp): 
    print "There was at least one number in our collect that was divisible by three" 
else: 
    print "There were no numbers in our collection divisible by three" 

雖然可以說,您將節省更多的時間執行使用循環這樣的邏輯。

and,而不是all

itr = 0 
result = True 
for i in collection_of_numbers: 
    if not i == itr: 
     result = False 
     break 
    itr += 100 
if result: 
    print "The numbers in our collection represent a linear set with slope 100" 
else: 
    print "The numbers in out collection do not represent a linear set with slope 100" 

的區別是這個檢查每一個條目,節約了大量的大型成套時間,其中一個初入門傷了你的條件之前,將打破。

or,而不是any

temp = [] 
result = False 
for i in collection_of_numbers: 
    if i%3 == 0: 
     result = True 
     break 
if result: 
    print "There was at least one number in our collect that was divisible by three" 
else: 
    print "There were no numbers in our collection divisible by three" 

這將檢查,直到它找到一個滿足的條件爲以後什麼都不會改變說法如何True是。

**編輯**上面使用短路短語和聲明證明的示例。 考慮

1 == 2 and 2 == 2 

all([1 == 2, 2 == 2]) 

第一條語句將評估1 == 2False和作爲一個整體的語句將immeadiately短路並evaulated到False。鑑於第二個陳述將評估1 == 2False,2 == 2True,則在進入功能and時,它現在將返回False。必須首先評估每條語句的額外步驟是爲什麼如果您正在檢查一些小型案例的有限布爾檢查以便不使用該函數,那麼這是更好的辦法。

雖然對於兩條語句無關緊要,但如果您舉一個極端例子,您會看到我對所有布爾語句的評估是短路的。下面的測試以不同的方式評估1000布爾語句,並以它們的執行時間爲單位。每條語句的第一個布爾語句將會在整個布爾語句上導致短路,但不會在評估上產生短路。

test.py

import timeit 

explicit_and_test = "1 == 0 and " + " and ".join(str(i) + " == " + str(i) for i in range(1000)) 

t = timeit.Timer(explicit_and_test) 
print t.timeit() 

function_and_test = "all([1 == 0, " + ", ".join(str(i) + " == " + str(i) for i in range(1000)) + "])" 

t = timeit.Timer(function_and_test) 
print t.timeit() 

setup = """def test_gen(n): 
    yield 1 == 0 
    for i in xrange(1,n): 
     yield i == i""" 

generator_and_test = "all(i for i in test_gen(1000))" 

t = timeit.Timer(generator_and_test,setup=setup) 
print t.timeit() 

當運行:

$ python test.py 
0.0311999320984  # explicit and statement 
26.3016459942  # List of statements using all() 
0.795602083206  # Generator using all() 

報表的短路評價的影響是顯而易見這裏由過高的因素。你可以看到,即使對於任何有限的布爾語句來說,最好的方法都是使用一個明確的語句,正如我在冗長的答案的開頭所述。這些函數適用於您可能不知道需要評估多少個布爾語句的情況。

+0

你的'any()'例子效率很低 - 爲什麼不使用生成器理解?事實上,使用三元運算符,你可以將它壓縮成一行:'print'foo'if if(i%3 == 0 for i in collection_of_numbers)else'bar'' – Air

+0

@AirThomas當你正確的時候,正如我提到的那樣,它們是用來明確說明「any」和「all」在做什麼的愚蠢示例,即對一組「boolean」進行評估。沒有任何_shortcuts_。我的答案意在進入明確和明顯的細節(可能以犧牲效率爲代價),因爲這個問題歸結爲理解這兩個內置命令的作用,以便能夠將它們的功能與顯式布爾語句。 –

+0

我很欣賞你爲這個答案付出的時間和精力,但你的前提是假的; 'any'和'all' [保證等同於你改寫爲'and'和'or']的函數(https://docs.python.org/2/library/functions.html#all),意味着[他們真的做了短路](http://stackoverflow.com/q/14730046/2359271)。爲了明確說明這些功能在做什麼,您需要發佈較低級別的源代碼。 – Air