欢迎光临散文网 会员登陆 & 注册

python列表count函数分析

2022-10-31 16:06 作者:真是累的很啊  | 我要投稿

看两个语句的内容以及执行的的结果

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,具体的我也没再试了,但足以证明,在对含有大量元素的列表进行统计时,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之适合于查找少量元素的总数或者统计小列表的元素,对于大列表还是直接遍历更快一点。


以上只是在假设count函数运行的过程是遍历的基础上,事后找到count源码才能真正知道原因。


python中list对象count方法c语言源码

方法体主要就是一个for循环,使用obj指针变量来每次指向列表中的元素,ob_item[i]就是存放列表中第i个元素地址的元素,他也是个指针,用obj和输入的value比较来实现值的比较,匹配则+1,继续下次循环,不匹配的话,接下来的语句由于我没学过c导致比较难理解:

py_incref函数和py_decref函数总是成对出现的,baidu加bing稍微有点小理解,这是对变量obj控制权的转移,至于为什么要转移,这可能和c中对引用数据的变量的管理有关,贴上官方对接下来那条关键语句的解释

  • int (PyObject *o1, PyObject *o2, int opidPyObject_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_LTPy_LEPy_EQPy_NEPy_GTPy_GE<<===!=>>=-101o1 op o2op

简单来说就是PyObject_RichCompareBool是一个做布尔运算的函数,通过o1 opid o2得出结果,在图中就是obj py_eq value,其中py_eq等价于==符号,下边的判断条件为cmp,上边的这个函数得到的结果有1(条件满足)0(条件不满足)-1(出现错误),当出现错误时会直接返回NULL,出现错误时可能时obj指向的内存没有数据了,也就是列表循环完了,就跳出循环了,最后再返回count值。

虽然对其他关于内存管理以及类方法的语句理解不了,但对于for语句也算能看懂,至少证明了count函数在用c实现的时候也是一种遍历,也就印证了个人的猜测。


python列表count函数分析的评论 (共 条)

分享到微博请遵守国家法律