98

Python では、文字列の連結と文字列の置換をいつどこで使用するのかわかりません。文字列の連結によりパフォーマンスが大幅に向上したため、これは実用的なものではなく、スタイル上の決定ですか?

具体的な例として、柔軟な URI の構築をどのように処理する必要があるかを示します。

DOMAIN = 'http://stackoverflow.com'
QUESTIONS = '/questions'

def so_question_uri_sub(q_num):
    return "%s%s/%d" % (DOMAIN, QUESTIONS, q_num)

def so_question_uri_cat(q_num):
    return DOMAIN + QUESTIONS + '/' + str(q_num)

編集:文字列のリストを結合し、名前付き置換を使用することについての提案もありました。これらは、いつどのように行うのが正しい方法であるかという中心的なテーマの変形です。回答ありがとうございます。

4

9 に答える 9

12

ループ内の文字列の連結には注意してください。 文字列連結のコストは、結果の長さに比例します。ループすると、N-squaredの土地に直接つながります。一部の言語は、最後に割り当てられた文字列への連結を最適化しますが、2次アルゴリズムを線形に最適化するためにコンパイラーを頼りにするのは危険です。join文字列のリスト全体を取得し、単一の割り当てを実行し、それらすべてを一度に連結するプリミティブ(?)を使用するのが最適です。

于 2008-12-18T04:40:07.623 に答える
8

好奇心から、さまざまな文字列連結/置換方法の速度をテストしていました。この件に関するグーグル検索で、ここにたどり着きました。誰かが決定するのに役立つことを期待して、テスト結果を投稿すると思いました.

    import timeit
    def percent_():
            return "test %s, with number %s" % (1,2)

    def format_():
            return "test {}, with number {}".format(1,2)

    def format2_():
            return "test {1}, with number {0}".format(2,1)

    def concat_():
            return "test " + str(1) + ", with number " + str(2)

    def dotimers(func_list):
            # runs a single test for all functions in the list
            for func in func_list:
                    tmr = timeit.Timer(func)
                    res = tmr.timeit()
                    print "test " + func.func_name + ": " + str(res)

    def runtests(func_list, runs=5):
            # runs multiple tests for all functions in the list
            for i in range(runs):
                    print "----------- TEST #" + str(i + 1)
                    dotimers(func_list)

... を実行した後runtests((percent_, format_, format2_, concat_), runs=5)、これらの小さな文字列で % メソッドが他のメソッドよりも約 2 倍高速であることがわかりました。concat メソッドは常に最も遅い (かろうじて) ものでした。この方法で位置を切り替えると、非常にわずかな違いがありましたが、位置のformat()切り替えは常に、通常のフォーマット方法よりも少なくとも 0.01 遅くなりました。

テスト結果のサンプル:

    test concat_()  : 0.62  (0.61 to 0.63)
    test format_()  : 0.56  (consistently 0.56)
    test format2_() : 0.58  (0.57 to 0.59)
    test percent_() : 0.34  (0.33 to 0.35)

スクリプトで文字列連結を使用しているため、これらを実行しましたが、コストはいくらか疑問に思っていました。それらをさまざまな順序で実行して、何も干渉していないことを確認したり、最初または最後にパフォーマンスを向上させたりしました。補足として、私はいくつかの長い文字列ジェネレーターをこれらの関数に投入しました。通常の concat は、 andメソッド"%s" + ("a" * 1024)を使用する場合のほぼ 3 倍 (1.1 対 2.8) 高速でした。それは文字列と、何を達成しようとしているかに依存すると思います。パフォーマンスが本当に重要な場合は、さまざまなことを試してテストすることをお勧めします。速度が問題にならない限り、速度よりも読みやすさを優先する傾向がありますが、それは私だけです。私のコピー/貼り付けが気に入らなかったので、正しく見えるようにすべてに8つのスペースを配置する必要がありました. 普段は4を使っています。format%

于 2013-05-13T03:27:35.843 に答える
4

コードの保守やデバッグを計画している場合、文体の決定実際的な決定であることを忘れないでください :-) Knuth からの有名な引用があります (おそらく Hoare を引用していますか?):時期尚早の最適化は諸悪の根源です。」

(たとえば) O(n) タスクを O(n 2 ) タスクに変えないように注意している限り、最も理解しやすいと思われる方を使用します..

于 2008-12-18T01:04:35.500 に答える
0

私は可能な限り代替を使用します。forループなどで文字列を構築する場合にのみ、連結を使用します。

于 2008-12-17T23:56:12.457 に答える
-1

Actually the correct thing to do, in this case (building paths) is to use os.path.join. Not string concatenation or interpolation

于 2011-08-20T03:56:37.653 に答える