python列表count函數分析
看兩個語句的內容以及執(zhí)行的的結果
1.
for i in list_all:
? ? dict1[i]=dict1.get(i,0)+1
2.
?for i in set(list_all):
? ? ?dict1[i]=list_all.count(i)

40ms的是1,1000ms的是2
一個運行花了1000多毫秒,一個40毫秒,差了接近30倍,根據測試,list_all中元素至少大于1500,不到5000,具體的我也沒再試了,但足以證明,在對含有大量元素的列表進行統(tǒng)計時,count函數的使用不盡人意,具體原因需要找到count源碼分析,猜測,count也是通過類似于遍歷的方法對列表中所有元素進行查找,這相當于我在對set(list_all)遍歷的基礎上,再對list_all遍歷,如果以遍歷的所有元素量代表速度,那么1代碼運行速度約等于len(list_all)+(1+len(dict1))*len(dict1)/2,2代碼運行速度約等于len(list_all)*len(set(list_all)),當list_all中元素很多且很少重復的時候,count運行速度明顯低的多,所以count之適合于查找少量元素的總數或者統(tǒng)計小列表的元素,對于大列表還是直接遍歷更快一點。
以上只是在假設count函數運行的過程是遍歷的基礎上,事后找到count源碼才能真正知道原因。


方法體主要就是一個for循環(huán),使用obj指針變量來每次指向列表中的元素,ob_item[i]就是存放列表中第i個元素地址的元素,他也是個指針,用obj和輸入的value比較來實現值的比較,匹配則+1,繼續(xù)下次循環(huán),不匹配的話,接下來的語句由于我沒學過c導致比較難理解:
py_incref函數和py_decref函數總是成對出現的,baidu加bing稍微有點小理解,這是對變量obj控制權的轉移,至于為什么要轉移,這可能和c中對引用數據的變量的管理有關,貼上官方對接下來那條關鍵語句的解釋
int?(PyObject?*o1,?PyObject?*o2, int?opid
PyObject_RichCompareBool
)Compare?the values of?o1?and?o2?using the operation specified by?opid, which must be one of?,?,?,?,?, or?, corresponding to?,?,?,?,?, or?respectively. Returns?on error,?if the result is false,?otherwise. This is the equivalent of the Python expression?, where?is the operator corresponding to?opid.
Py_LT
Py_LE
Py_EQ
Py_NE
Py_GT
Py_GE
<
<=
==
!=
>
>=
-1
0
1
o1?op?o2
op
簡單來說就是PyObject_RichCompareBool是一個做布爾運算的函數,通過o1 opid o2得出結果,在圖中就是obj py_eq value,其中py_eq等價于==符號,下邊的判斷條件為cmp,上邊的這個函數得到的結果有1(條件滿足)0(條件不滿足)-1(出現錯誤),當出現錯誤時會直接返回NULL,出現錯誤時可能時obj指向的內存沒有數據了,也就是列表循環(huán)完了,就跳出循環(huán)了,最后再返回count值。
雖然對其他關于內存管理以及類方法的語句理解不了,但對于for語句也算能看懂,至少證明了count函數在用c實現的時候也是一種遍歷,也就印證了個人的猜測。