¿Por qué el inicio de la cadena es más lento que en?
Sorprendentemente, encuentrostartswith
es más lento quein
:
In [10]: s="ABCD"*10
In [11]: %timeit s.startswith("XYZ")
1000000 loops, best of 3: 307 ns per loop
In [12]: %timeit "XYZ" in s
10000000 loops, best of 3: 81.7 ns per loop
Como todos sabemos, elin
la operación necesita buscar en toda la cadena ystartswith
solo necesita verificar los primeros caracteres, así questartswith
Debería ser más eficiente.
Cuandos
es lo suficientemente grandestartswith
es más rápido:
In [13]: s="ABCD"*200
In [14]: %timeit s.startswith("XYZ")
1000000 loops, best of 3: 306 ns per loop
In [15]: %timeit "XYZ" in s
1000000 loops, best of 3: 666 ns per loop
Entonces parece que llamarstartswith
tiene algo de sobrecarga que lo hace más lento cuando la cadena es pequeña.
Y luego traté de averiguar cuál es la sobrecarga delstartswith
llamada.
Primero, usé unf
variable para reducir el costo de la operación de puntos, como se menciona en esteresponder - aquí podemos verstartswith
sigue siendo más lento
In [16]: f=s.startswith
In [17]: %timeit f("XYZ")
1000000 loops, best of 3: 270 ns per loop
Además, probé el costo de una llamada de función vacía:
In [18]: def func(a): pass
In [19]: %timeit func("XYZ")
10000000 loops, best of 3: 106 ns per loop
Independientemente del costo de la operación de punto y la llamada de función, el tiempo destartswith
es aproximadamente (270-106) = 164ns, pero elin
la operación solo requiere 81.7ns. Parece que todavía hay algunos gastos generales parastartswith
, ¿que es eso?
Agregue el resultado de la prueba entrestartswith
y__contains__
según lo sugerido por poke y lvc:
In [28]: %timeit s.startswith("XYZ")
1000000 loops, best of 3: 314 ns per loop
In [29]: %timeit s.__contains__("XYZ")
1000000 loops, best of 3: 192 ns per loop