web-dev-qa-db-ja.com

文字列のstartswithがinより遅いのはなぜですか?

驚いたことに、startswithinよりも遅いことがわかりました。

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
55
WKPlus

これは、str.startswith()str.__contains__()よりも多くのことを実行していること、および_str.__contains___がCで完全に動作しているのに対し、str.startswith()は=と対話する必要があるためと考えられますPython types。そのシグネチャはstr.startswith(prefix[, start[, end]])です。ここで、prefixは試行する文字列のタプルです。

1
Cyphase