2017-03-04 31 views
5

快這是莫名其妙的後續這個question可以總結上列出

因此,首先,你會發現,你不能字符串列表上執行sum將它們串聯,蟒蛇告訴你使用str.join取而代之,這是很好的建議,因爲無論你如何在字符串上使用+,性能都很糟糕。

「不能使用sum」限制不適用於list,儘管itertools.chain.from_iterable是執行此類列表展平的首選方式。

sum(x,[])x是列表的列表是肯定不好的。

但是它應該保持那種方式嗎?

我比3接近

import time 
import itertools 

a = [list(range(1,1000)) for _ in range(1000)] 

start=time.time() 
sum(a,[]) 
print(time.time()-start) 

start=time.time() 
list(itertools.chain.from_iterable(a)) 
print(time.time()-start) 


start=time.time() 
z=[] 
for s in a: 
    z += s 
print(time.time()-start) 

結果:列出的名單上

  • sum():10.46647310256958。好的,我們知道。
  • itertools.chain:0.07705187797546387
  • 使用自定義的積累和就地另外:0.057044029235839844(可快於itertools.chain正如你看到的)

所以sum是遠遠落後,因爲它執行的result = result + b代替result += b

所以,現在我的問題:

爲什麼不能sum可用時,這種累積方法可用樂?

(這將是透明的,已經存在的應用程序和將使得有可能使用的sum內置扁平化高效名單)

回答

4

我們可以試着讓總和()聰明,但亞歷克斯·馬爾泰利和Guido van Rossum想保持專注於算術總和。

FWIW,你應該得到合理的性能,這個簡單的代碼:

result = [] 
for seq in mylists: 
    result += seq 

對於你的另一個問題,「爲什麼不能總結可用時使用此累計法?」,看到builtin_sum此評論()在Python/bltinmodule.c:

/* It's tempting to use PyNumber_InPlaceAdd instead of 
     PyNumber_Add here, to avoid quadratic running time 
     when doing 'sum(list_of_lists, [])'. However, this 
     would produce a change in behaviour: a snippet like 

     empty = [] 
     sum([[x] for x in range(10)], empty) 

     would change the value of empty. */ 
+0

也許可以調整它以檢查'empty'是否爲空,並且在這種情況下使用另一個空列表(或者如果不是太大,則創建一個副本)。這將是透明的,不會花費大量的CPU(複製評論對另一個答覆者) –

+2

語言設計是非常微妙的。棘手的調整可能會導致其他意想不到的行爲。如果人們習慣於使用* sum()*作爲非數字工作,那麼他們更有可能陷入與其他類型的二次行爲中,例如'sum(list_of_tuples,())'或'sum( list_of_sets,set())''。即使這些是高性能的,仍然存在一些問題,即* sum *這個詞是否是表達* concatenate *或* set.union *或「flatten」的業務邏輯概念的最明確方式。 Guido的設計本能有着出色的記錄。對BDFL進行第二次猜測是危險的;-) –

+0

這是一個很好的觀點。在這種情況下,爲什麼我們不能阻止像sum這樣巧妙地使用字符串的情況?也許在Python 4? –

1
/* It's tempting to use PyNumber_InPlaceAdd instead of 
      PyNumber_Add here, to avoid quadratic running time 
      when doing 'sum(list_of_lists, [])'. However, this 
      would produce a change in behaviour: a snippet like 
      empty = [] 
      sum([[x] for x in range(10)], empty) 
      would change the value of empty. */ 
temp = PyNumber_Add(result, item); 

來自Python的內置源代碼https://github.com/python/cpython/blob/master/Python/bltinmodule.c#L2146 線:2342

+1

不錯的發現!說得通。一次我不介意「代碼唯一的答案」 –

+0

也許可以調整它以檢查'empty'是否爲空,並且在這種情況下使用另一個空列表(或者如果不是太大,則創建一個副本)。這將是透明的,並不會花費大量的CPU ...如果Guido讀取... :) –

+0

是做內部使用副本會做的伎倆..此外,也不會有任何兼容性問題。 。 –

1

FWIW,我們可以欺騙翻譯讓我們在字符串上使用sum,方法是將適當的自定義類實例作爲start arg傳遞給sum

class Q(object): 
    def __init__(self, data=''): 
     self.data = str(data) 

    def __str__(self): 
     return self.data 

    def __add__(self, other): 
     return Q(self.data + str(other)) 

print(sum(['abc', 'def', 'ghi'], Q())) 

輸出

abcdefghi 

當然,這做一個相當愚蠢的事。 :)

+0

愚蠢,但同樣的事情可以用'__add__'編寫的就地添加的列表完成,所以這是個好主意。 –

+0

@ Jean-FrançoisFabre我想是這樣,但很難與雷蒙德的觀點爭辯。 OTOH,而不是調整'sum'來有效地處理這個操作,'list'可以得到一個新的方法,例如'.merge'(給它一個'.join'方法會導致一個混亂的世界)。 –

+0

好主意,並且阻止'sum'(但是這會破壞一些程序,就像'xrange' =>'range'一樣。 –