2013-03-15 68 views
1

我已經在Python,其中ori是一個字符串Python能否避免在語句中重新評估?

 
[ori[ori.rfind(' ') + 1:], ori[:ori.rfind(' ')]] 

我們可以看到ori.rfind(」「)被調用了兩次,是解釋足夠聰明下面的語句只是計算函數只有一次?

我們可以做到以下幾點:

 
    s = ori.rfind(' ') 
    return [ori[s+1:], ori[:s]] 

但這種利用兩行。我打算在列表理解中使用這個語句,並希望這個函數是一行。

在這種情況下,解釋器實際上更容易理解,因爲字符串是不可變的。我的猜測可能是解釋者可以聰明地避免重新評估。一般來說,如果對象是不可變的,解釋器是否足夠聰明?

+1

「使用兩行很少pythonic」?! – NPE 2013-03-15 17:29:18

+3

爲什麼它會變得不那麼pythonic? – 2013-03-15 17:29:27

+0

在幾乎所有情況下,使用兩行*都是不正確的*。當它是正確的時候,它很少重要。當它是正確的並且很重要時,通常很難自動完成。 – delnan 2013-03-15 17:34:40

回答

2

解釋器可以安全地執行子表達式ori.rfind(' ')的唯一方法是一次,如果它知道

  1. 的RFIND表達沒有進行任何突變
  2. 第一和第二使用rFind之間沒有表情引起的任何突變

如果有任何這不是真的,那麼緩存結果和重用會根本不安全。鑑於Python的動態特性,幾乎不可能擁有這些保證,因此像這樣的操作無法緩存+重用

+0

+1,這是一個非常好的解釋,爲什麼建議的優化不起作用。 – 2013-03-15 17:43:12

+0

@Lattyware公平地說,真正的問題是可以在任何角落重新定義方法。提到的所有其他問題都由Java共享,但Hotspot JIT在優化代碼時沒有問題(假設'rfind'不會影響內聯預算)。事實上,熱點設法消除虛擬調用並修復問題,如果它的假設後來失效,因此只要有足夠的工程努力,就沒有任何東西可以阻止python運行時間這樣做。 – Voo 2013-03-15 17:50:59

+1

正在重新定義的方法只是突變的一個特例。 – 2013-03-15 17:52:41

5

我不認爲你可以指望解釋評估函數只有一次,但這裏是您當前的代碼等量替代是短,類似於效率兩線法:

ori.rsplit(' ', 1)[::-1] 

實施例和定時比較:

In [1]: ori = 'foo bar baz' 

In [2]: [ori[ori.rfind(' ') + 1:], ori[:ori.rfind(' ')]] 
Out[2]: ['baz', 'foo bar'] 

In [3]: ori.rsplit(' ', 1)[::-1] 
Out[3]: ['baz', 'foo bar'] 

In [4]: %timeit [ori[ori.rfind(' ') + 1:], ori[:ori.rfind(' ')]] 
1000000 loops, best of 3: 732 ns per loop 

In [5]: %timeit ori.rsplit(' ', 1)[::-1] 
1000000 loops, best of 3: 514 ns per loop 

In [6]: %timeit s = ori.rfind(' '); [ori[s+1:], ori[:s]] 
1000000 loops, best of 3: 490 ns per loop 
+0

(+1)不知道有' rsplit()'。 – NPE 2013-03-15 17:32:08

+0

真的很感謝你提到rsplit以及實驗!但我覺得另一個答覆更直接地回答了我的問題,所以我接受了這個答案。 – szli 2013-03-15 20:48:03