12

私は誤ってPythonでフォームの操作を見つけました

string1.join(string2)

同等に表現することができます

string2.replace('', string1)[len(string1):-len(string1)]

さらに、いくつかの異なるサイズの入力を試しtimeitた後、この奇妙な参加方法は2倍以上速いようです。

  1. なぜjoinメソッドを遅くする必要があるのですか?
  2. このように空の文字列を置き換えることは安全で明確なことですか?
4

2 に答える 2

5

Lattyware が述べたように、空の文字列の置換については、それは特別なケースでreplace_interleaveあり、ソースと文字列からの代替文字が結果の文字列にコピーされる単純なループです。ループは可能な限り高速になるようにコーディングされています。

count = self_len+1;

count -= 1;
Py_MEMCPY(result_s, to_s, to_len);
result_s += to_len;
for (i=0; i<count; i++) {
    *result_s++ = *self_s++;
    Py_MEMCPY(result_s, to_s, to_len);
    result_s += to_len;
}

/* Copy the rest of the original string */
Py_MEMCPY(result_s, self_s, self_len-i);

Join メソッドにもループがありますが、改善の領域 (次のようにコード化された理由のすべての側面を見つけたわけではありません) とボトルネックの理由があります。

char *sep = PyString_AS_STRING(self);
seq = PySequence_Fast(orig, "");
/* Catenate everything. */
p = PyString_AS_STRING(res);
for (i = 0; i < seqlen; ++i) {
    size_t n;
    item = PySequence_Fast_GET_ITEM(seq, i);
    n = PyString_GET_SIZE(item);
    Py_MEMCPY(p, PyString_AS_STRING(item), n);
    p += n;
    if (i < seqlen - 1) {
        Py_MEMCPY(p, sep, seplen);
        p += seplen;
    }
}

ここでわかるように、ループの内側

  • 文字列の各項目にインデックスが付けられます
  • アイテムのサイズが決定されます
  • インデックス付きアイテムが文字列に変換される

上記の 3 つの操作は、インライン化されている場合でも、かなりのオーバーヘッドがあります。これは、Blended で観察されたように、リストを使用すると STring を使用する場合と比較して結果が異なる理由についても説明しています。

また、両方のループを比較すると、

前者

ファイナルノート

str.join、文字列だけでなく、すべての形式の iterable とシーケンスを念頭に置いて作成されました。詳しくは説明しませんが、一般化されたルーチンは、特定の形式のデータを提供する特殊なルーチンほど速く実行されない可能性があることが予想されます。

于 2013-01-21T03:58:13.757 に答える
5

それではまず、なぜこれが機能するのかを分析しましょう。

>>> string1 = "foo"
>>> string2 = "bar"
>>> string1.join(string2)
'bfooafoor'

string1の項目(文字)ごとに挟む操作ですstring2

したがって、空の文字列を置き換えると、何か興味深いことが起こります。空の文字間のギャップを空の文字列としてカウントするため、最初と最後に余分な区切り記号があることを除いて、本質的に同じタスクを実行します。

>>> string2.replace('', string1)
'foobfooafoorfoo'

したがって、これらを切り出すと、次と同じ結果が得られstr.join()ます。

>>> string2.replace('', string1)[len(string1):-len(string1)]
'bfooafoor'

明らかに、この解決策は よりはるかに読みにくいstr.join()ため、私は常にそれをお勧めしません。str.join()また、すべてのプラットフォームで効率的に動作するように開発されています。空の文字列を置き換えると、Python の一部のバージョンでは効率が大幅に低下する可能性があります (そうであるかどうかはわかりませんが、可能性はあります。CPython では連結の繰り返しがかなり高速ですが、他のバージョンでは必ずしもそうとは限りません)。

空の文字列を置き換えるこの動作がこのように機能することを示唆するドキュメントは何も見つかりません。ドキュメントはstr.replace()単に次のように述べています。

部分文字列 old をすべて new に置き換えた文字列のコピーを返します。オプションの引数 count が指定されている場合、最初の count 個の出現のみが置き換えられます。

文字間のギャップが空の文字列の出現としてカウントされるべきであると推定する理由がわかりません (おそらく、文字列のどこにでも無限の空の文字列を収めることができます)。考え。

この操作も非常にまれです。一連の文字列を結合する方が一般的です。文字列の個々の文字を結合することは、私が個人的に頻繁に行う必要があることではありません。

興味深いことに、これは Python ソースx.replace("", y)では特殊なケースのようです:

2347 /* Algorithms for different cases of string replacement */
2348
2349 /* len(self)>=1, from="", len(to)>=1, maxcount>=1 */
2350 Py_LOCAL(PyStringObject *)
2351 replace_interleave(PyStringObject *self,
2352 const char *to_s, Py_ssize_t to_len,
2353 Py_ssize_t maxcount)
2354 {
...

この特別なケーシングがうまく機能させるのかもしれません. 繰り返しますが、ドキュメントには記載されていないため、これは実装の詳細であり、他の Python バージョンでも同じように (またはまったく) 動作すると仮定するのは間違いです。

于 2013-01-21T03:05:57.200 に答える