文字列の連結とPythonでの文字列置換
-
22-08-2019 - |
質問
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)
編集:文字列のリストを結合したり、名前付き置換を使用したりすることについての提案もあります。これらは、どのタイミングでどの方法を行うのが正しいのかという中心テーマのバリエーションです。ご回答ありがとうございました!
解決
連結は、私のマシンに応じて(大幅に)高速です。しかし、文体、私はパフォーマンスが重要でない場合は代替の価格を支払うことを喜びました。私はフォーマットする必要がある場合はまあ、及び、でも質問をする必要はありません...補間/テンプレートを使用するが、オプションはありません。
>>> import timeit
>>> def so_q_sub(n):
... return "%s%s/%d" % (DOMAIN, QUESTIONS, n)
...
>>> so_q_sub(1000)
'http://stackoverflow.com/questions/1000'
>>> def so_q_cat(n):
... return DOMAIN + QUESTIONS + '/' + str(n)
...
>>> so_q_cat(1000)
'http://stackoverflow.com/questions/1000'
>>> t1 = timeit.Timer('so_q_sub(1000)','from __main__ import so_q_sub')
>>> t2 = timeit.Timer('so_q_cat(1000)','from __main__ import so_q_cat')
>>> t1.timeit(number=10000000)
12.166618871951641
>>> t2.timeit(number=10000000)
5.7813972166853773
>>> t1.timeit(number=1)
1.103492206766532e-05
>>> t2.timeit(number=1)
8.5206360154188587e-06
>>> def so_q_tmp(n):
... return "{d}{q}/{n}".format(d=DOMAIN,q=QUESTIONS,n=n)
...
>>> so_q_tmp(1000)
'http://stackoverflow.com/questions/1000'
>>> t3= timeit.Timer('so_q_tmp(1000)','from __main__ import so_q_tmp')
>>> t3.timeit(number=10000000)
14.564135316080637
>>> def so_q_join(n):
... return ''.join([DOMAIN,QUESTIONS,'/',str(n)])
...
>>> so_q_join(1000)
'http://stackoverflow.com/questions/1000'
>>> t4= timeit.Timer('so_q_join(1000)','from __main__ import so_q_join')
>>> t4.timeit(number=10000000)
9.4431309007150048
他のヒント
という名前の置換を忘れないでください。
def so_question_uri_namedsub(q_num):
return "%(domain)s%(questions)s/%(q_num)d" % locals()
をループ内で文字列を連結するのを警戒して!の文字列連結のコストは、結果の長さに比例します。ループは、ストレートN乗の土地にあなたを導き。一部の言語では、最も最近に割り当てられた文字列への連結を最適化しますが、それはリニアに至るまで、あなたの次のアルゴリズムを最適化するために、コンパイラにカウントすることは危険です。ベストプリミティブ(join
?)を使用するには、文字列のリスト全体を受け取り、単一の割り当てを行い、かつ一度にそれらすべてを連結している。
「文字列連結は、パフォーマンスに大きなブーストを見たように...」
は、パフォーマンスの問題ならば、これは知って良いです。
しかし、私が見たパフォーマンスの問題は、文字列操作に降りてくることがありません。私は一般的にI / Oを、ソートやO(のN の 2 )の操作がボトルネックであることとのトラブルに得ている。
文字列操作は、パフォーマンスのリミッターがあるまでは、私は明らかにされているものに固執するだろう。それは1行またはそれが理にかなって少なく、連結、および(マコのような)テンプレートツールだとき、それは大だとき、主に、それは置換があります。
何を連結/補間するか、結果をどのようにフォーマットするかによって決定が決まります。
文字列補間を使用すると、書式設定を簡単に追加できます。実際、文字列補間バージョンは連結バージョンと同じことを行いません。実際には、前に余分なスラッシュが追加されます。
q_num
パラメータ。同じことをするには、次のように書く必要がありますreturn DOMAIN + QUESTIONS + "/" + str(q_num)
その例では。補間により、数値の書式設定が容易になります。
"%d of %d (%2.2f%%)" % (current, total, total/current)
連結形式でははるかに読みにくくなります。連結は、文字列化する項目の数が固定されていない場合に便利です。
また、Python 2.6 では、と呼ばれる新しいバージョンの文字列補間が導入されていることにも注意してください。 文字列テンプレート:
def so_question_uri_template(q_num):
return "{domain}/{questions}/{num}".format(domain=DOMAIN,
questions=QUESTIONS,
num=q_num)
文字列テンプレートは最終的には %-interpolation に取って代わられる予定ですが、それはしばらくの間は起こらないと思います。
私は好奇心のうち異なる文字列の連結/置換方法の速度をテストしていました。対象のGoogle検索はここで私をもたらしました。私はそれが誰かを決定するのに役立つかもしれないことを期待して、私のテスト結果を投稿するだろうと思っています。
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)
私は私のスクリプトで文字列の連結を使用して行うので、私はこれらを走った、と私はコストが何であったかと思いまして。私は、干渉、または最初または最後のものより優れた性能を得ていたことを確認何をしないために異なる順序でそれらを実行しました。サイドノートでは、私は"%s" + ("a" * 1024)
とformat
メソッドを使用するなど(1.1 2.8対)のほぼ3倍の速さだった%
と定期的な連結と同様に、これらの機能の中に、いくつかの長い文字列の生成に投げました。私はそれを文字列に依存して推測し、何を達成しようとしています。パフォーマンスが重要な場合は、別のものを試してみて、それらをテストする方が良いかもしれません。私はスピードが問題になる場合を除き、スピードオーバー可読性を選択する傾向があるが、ちょうど私のthats。 SO私のコピー/貼り付けを好きではなかった、私はそれを右に見えるようにすべてのものの上に8つのスペースを入れていました。私は通常4を使用します。
を忘れないでください、文体の決定は、のあるの実用的な意思決定、あなたは今までクヌース(おそらくホーアを引用?)からの有名な言葉があります:-)維持またはあなたのコードをデバッグする上で計画している場合:「我々は小さな忘れる必要があります効率は、時間の約97%を言う:時期尚早の最適化は諸悪の根源である「
。限り、あなたは(例えば)OにO(n)のタスクをオンにしないように注意しているとして(N 2 )タスクは、私はあなたが理解するのが最も簡単見つけ方となるだろう。..
私は、置換を使用しています。 forループと言うには、私は、文字列を構築していた場合、私は唯一の連結を使用します。
実際に行うには正しい事は、この場合には(パスの構築)os.path.join
を使用することです。ない文字列の連結または補間