驚いたことに、startswith
はin
よりも遅いことがわかりました。
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
ご存じのとおり、in
操作では文字列全体を検索する必要があり、startswith
は最初の数文字を確認するだけでよいため、startswith
の方が効率的です。
s
が十分に大きい場合、startswith
の方が高速です。
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
したがって、startswith
の呼び出しにはオーバーヘッドがあり、文字列が小さい場合に遅くなるようです。
そして、startswith
呼び出しのオーバーヘッドが何であるかを理解しようとしました。
最初に、ドット操作のコストを削減するためにf
変数を使用しました-これで述べたように answer -ここで、startswith
がまだ遅いことがわかります。
In [16]: f=s.startswith
In [17]: %timeit f("XYZ")
1000000 loops, best of 3: 270 ns per loop
さらに、空の関数呼び出しのコストをテストしました。
In [18]: def func(a): pass
In [19]: %timeit func("XYZ")
10000000 loops, best of 3: 106 ns per loop
ドット操作と関数呼び出しのコストに関係なく、startswith
の時間は約(270-106)= 164nsですが、in
操作には81.7nsしかかかりません。 startswith
にはまだオーバーヘッドがあるようですが、それは何ですか?
Pokeとlvcの提案に従って、テスト結果をstartswith
と__contains__
の間に追加します。
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
これは、str.startswith()
がstr.__contains__()
よりも多くのことを実行していること、および_str.__contains__
_がCで完全に動作しているのに対し、str.startswith()
は=と対話する必要があるためと考えられますPython types。そのシグネチャはstr.startswith(prefix[, start[, end]])
です。ここで、prefixは試行する文字列のタプルです。