2009-01-24 138 views
10

網上有很多關於python性能的文章,您首先閱讀的內容是:連接字符串不應該使用'+'來完成:避免使用s1 + s2 + s3,而使用str.joinpython字符串連接性能

我試過如下:連接兩個字符串作爲目錄路徑的一部分:三種方法:

  1. '+',我不應該這樣做
  2. str.join
  3. os.path.join

這裏是我的代碼:

import os,time 

s1='/part/one/of/dir' 
s2='part/two/of/dir' 
N=10000 

t=time.clock() 
for i in xrange(N): 
    s=s1+os.sep+s2 
print time.clock()-t 

t=time.clock() 
for i in xrange(N): 
    s=os.sep.join((s1,s2)) 
print time.clock()-t 

t=time.clock() 
for i in xrange(N): 
    s=os.path.join(s1,s2) 
print time.clock()-t 

這裏的結果(Python 2.5中的WinXP)

0.0182201927899 
0.0262544541275 
0.120238186697 

它不應該是完全倒過來?

+1

如果我可以,我建議重命名你的問題「Python字符串連接性能」的稱號,只是這樣它更明顯,誰可能提交重複的問題的人。 – 2009-01-24 22:35:21

+1

此外,主題略有偏離,但您可能需要查看'timeit'模塊以進行計時。 – 2009-01-24 22:35:59

回答

4

確實,你不應該使用'+'。你的例子是相當特別的,嘗試使用相同的代碼:

s1='*'*100000 
s2='+'*100000 

然後第二個版本(str.join)快得多。

12

字符串連接的大多數性能問題都是漸近性能問題,所以當您連接很多長字符串時,差異會變得最爲重要。在您的示例中,您正在多次執行相同的級聯。你沒有建立任何長字符串,可能是python解釋器正在優化你的循環。這可以解釋爲什麼當你移動到str.join和path.join時,時間會增加 - 它們是更復雜的函數,並不容易被減少。 (os.path.join會對字符串進行很多檢查,看它們是否需要在連接之前以任何方式進行重寫。爲了便於攜帶,這犧牲了一些性能。)

順便說一句,既然文件路徑通常不會很長,爲了便於攜帶,幾乎可以肯定地使用os.path.join。如果連接的性能是一個問題,那麼你對文件系統做了一些非常奇怪的事情。

5

它不應該完全相反嗎?

不一定。我不清楚Python的內部結構是否足夠詳細,但是一些常見的觀察是你的第一個循環使用了一個簡單的運算符+,它很容易被運行時實現爲基元。相比之下,其他循環首先必須解析模塊名稱,解析在那裏找到的變量/類,然後調用其上的成員函數。

另一個需要注意的是你的循環可能太小而不能產生顯着的數字。考慮到你的整體運行時間很少,這可能會讓你的測試失效。

另外,您的測試用例對兩個短字符串高度專業化。這種情況從來不能清楚地說明邊緣案件的表現。

4

該建議是關於連接很多字符串。

要計算s = s1 + s2 + ...+ sn,

1)使用+。創建一個新的字符串s1 + s2,然後創建一個新的字符串s1 + s2 + s3,...等等,因此涉及大量的內存分配和複製操作。實際上,s1被複制n-1次,s2被複制n-2次,...等。

2)使用「」.join([s1,s2,...,sn])。連接完成一次,字符串中的每個字符只被複製一次。

在你的代碼中,每次迭代都會調用join,所以就像使用+一樣。正確的方法是收集數組中的項目,然後調用join。

編輯:固定錯字

1

字符串連接(+)具有上CPython的一個優化的實施方式。但是在Jython或IronPython等其他體系結構上可能並非如此。所以當你希望你的代碼在這些解釋器上很好地執行時,你應該在字符串上使用.join()方法。 os.path.join()專門用於加入文件系統路徑。它也處理不同的路徑分隔符。這將是構建文件名的正確方法。

0

我想添加一個鏈接到python維基,其中有關於字符串連接的註釋,並且「這一部分在python2.5中有些不對,Python 2.5字符串連接是相當快的」。

我相信字符串連接自2.5以來有了很大的改進,儘管str.join仍然更快(特別是對於大字符串),但您不會看到像舊版Python版本那樣的改進。

http://wiki.python.org/moin/PythonSpeed/PerformanceTips#StringConcatenation