2014-10-26 42 views
6

這主要是一個學習Python的練習。我寫了這個功能來測試一個數是否爲素數:任何表演()

def p1(n): 
    for d in xrange(2, int(math.sqrt(n)) + 1): 
     if n % d == 0: 
      return False 
    return True 

然後我意識到,我可以很容易地使用任何()重寫一遍:

def p2(n): 
    return not any((n % d == 0) for d in xrange(2, int(math.sqrt(n)) + 1)) 

性能的角度來看,我期待P2是比,或者至少是一樣快,快,P1因爲任何()是內置的,但對於一個大十歲上下的壯年,P2是一個相當慢一點:

$ python -m timeit -n 100000 -s "import test" "test.p1(999983)" 
100000 loops, best of 3: 60.2 usec per loop 

$ python -m timeit -n 100000 -s "import test" "test.p2(999983)" 
100000 loops, best of 3: 88.1 usec per loop 

我使用的任何()不正確地在這裏?有沒有辦法使用any()編寫這個函數,這樣它就像迭代自己一樣?

更新:編號爲更大的首要

$ python -m timeit -n 1000 -s "import test" "test.p1(9999999999971)" 
1000 loops, best of 3: 181 msec per loop 

$ python -m timeit -n 1000 -s "import test" "test.p2(9999999999971)" 
1000 loops, best of 3: 261 msec per loop 
+0

看到https://docs.python.org/2/library/functions.html#any它看起來很像你寫的東西。 – njzk2 2014-10-26 22:24:29

+1

@rightføld增加50%是一個小小的差異? – Barmar 2014-10-26 22:28:01

+0

不是,但<1000次迭代是一個足夠小的數字,以至於與循環體相比,幾個額外的堆棧幀(更不用說當時在計算機中其他地方發生的事情)仍然很重要。 – 2014-10-26 22:31:57

回答

4

的性能差異是最小的,但它存在的原因是,any招致建設發生器的表達,和一個額外的函數調用,相比for循環。儘管(快捷評估),兩者都有相同的行爲。

隨着輸入規模的增長,差異不會減少(我錯了),因爲你使用了一個生成器表達式,並且迭代它需要調用一個方法(.next())和一個額外的堆棧幀。當然,這是在引擎蓋下做的。

for循環遍歷一個對象xrangeany正在迭代一個生成器表達式,該生成器表達式本身正在遍歷一個對象。

無論哪種方式,請使用哪一個產生最可讀/可維護的代碼。如果選擇其中之一,那麼對於您正在編寫的任何程序的性能影響很小(如果有的話)。

+0

謝謝。我知道他們有相同的行爲,只是嘗試學習內建函數的正確用法,因爲我是Python新手。但是我看不出差距會縮小甚至更大的素數(我會稍微更新這個問題)。即使是13位的素數,差異仍然在50%左右(約180ms vs約270ms)。關於可讀性,我明白你的觀點,但對於這個特定的練習,我更感興趣的是理解任何()的用法。 – linus 2014-10-26 22:53:52

+0

謝謝。這就說得通了。我不同意它沒有任何性能影響。一個實現似乎一直比另一個慢50%,所以取決於這個函數被調用的頻率,可能會有顯着的性能差異。這就是說,關於發生器表達式的觀點對我來說是完全有意義的。謝謝! – linus 2014-10-26 23:28:27

+0

那麼,像往常一樣,寫工作,可讀的代碼,然後*配置文件和優化。總是按照這個順序;) – 2014-10-26 23:34:20