Pythonインタープリターにとってのバックティックの意味: `num`


87

私はリスト内包表記で遊んでいて、別のサイトでこの小さなスニペットに出くわしました:

return ''.join([`num` for num in xrange(loop_count)])

`num`ビットを壊すことに気付く前に、(タイピングによって)関数を複製するのに数分費やしました。

これらの文字でステートメントを囲むとどうなりますか?私が見ることができるものから、それはstr(num)と同等です。しかし、私が時間を計ったとき:

return ''.join([str(num) for num in xrange(10000000)])

4.09秒かかりますが、

return ''.join([`num` for num in xrange(10000000)])

2.43秒かかります。

どちらも同じ結果になりますが、1つはかなり遅くなります。ここで何が起こっているのですか?

編集:奇妙なことに... repr()は、よりも少し遅い結果を与え`num`ます。2.99秒vs 2.43秒。Python 2.6を使用します(3.0はまだ試していません)。


8
skymind.com/~ocrow/python_stringの「別のサイト」を読んだ後、同様の質問があり、このページを見つけました。いい質問といい答え:)
netvope

回答:


122

バックティックは、の非推奨のエイリアスですrepr()。もう使用しないでください。構文はPython 3.0で削除されました。

バッククォートを使用すると、使用するよりも速くなるように思われるrepr(num)か、num.__repr__()バージョン2.xの中で これは、グローバル名前空間(の場合repr)またはオブジェクトの名前空間(の場合__repr__)でそれぞれ追加の辞書検索が必要になるためだと思います。


disモジュールを使用すると、私の仮定が証明されます。

def f1(a):
    return repr(a)

def f2(a):
    return a.__repr__()

def f3(a):
    return `a`

分解ショー:

>>> import dis
>>> dis.dis(f1)
  3           0 LOAD_GLOBAL              0 (repr)
              3 LOAD_FAST                0 (a)
              6 CALL_FUNCTION            1
              9 RETURN_VALUE
>>> dis.dis(f2)
  6           0 LOAD_FAST                0 (a)
              3 LOAD_ATTR                0 (__repr__)
              6 CALL_FUNCTION            0
              9 RETURN_VALUE        
>>> dis.dis(f3)
  9           0 LOAD_FAST                0 (a)
              3 UNARY_CONVERT       
              4 RETURN_VALUE   

f1のグローバルルックアップreprf2の属性ルックアップが必要__repr__ですが、バックティック演算子は別のオペコードに実装されています。辞書検索(LOAD_GLOBAL/ LOAD_ATTR)や関数呼び出し(CALL_FUNCTION)のオーバーヘッドがないため、バックティックの方が高速です。

Pythonの人々は、個別の低レベルの操作を行うことrepr()は価値がないと判断し、両方repr()とバックティックを使用することは原則に違反すると判断したと思います

「それを行うには、明白な方法が1つ(できれば1つだけ)あるべきです。」

そのため、この機能はPython 3.0で削除されました。


どのようにしてバックティックを関数呼び出しに置き換えることができるかを見つけたかったのですが、それは不可能のようです、またはそうですか?
Jiri、

2
バッククォートの代わりにrepr()を使用してください。バックティックはrepr()の廃止された構文であり、3.0に付属しています。ANOTHER関数を呼び出すよりも、実際にはバックティックの外観を好みます。
Dominic Bou-Samra

8
バックティックが廃止された理由は、 `文字自体が原因でもあります。入力が難しい(一部のキーボードでは)、それが何であるかがわかりにくい、Pythonの本で正しく印刷するのが難しい場合があります。その他
u0b34a0f6ae 2009年

4
@ kaizer.se:指摘いただきありがとうございます。これがおそらくバッククォートを削除する主な理由です。メーリングリストアーカイブのGuidosステートメントをご覧ください:mail.python.org/pipermail/python-ideas/2007-January/000054.html
Ferdinand Beyer

これが投稿された元の質問は、キーボードでバックティックを実際に見つけることができなかったためでした;)チルドの下では、グーグルした後のようです。
Dominic Bou-Samra

10

バックティッククォートは一般に役に立たず、Python 3ではなくなりました。

それが価値があるもののために、これ:

''.join(map(repr, xrange(10000000)))

私にとっては、バックティックバージョンよりわずかに高速です。しかし、これを心配することはおそらく時期尚早の最適化です。


2
リスト/イテレータ内包表記ではなくマップを使用する理由は何ですか?
nikow 2009年

4
実際には、の場合よりもtimeit結果が速くなります(の場合はさらに悪い)。少しがっかりです;-)''.join(map(repr, xrange(0, 1000000)))''.join([repr(i) for i in xrange(0, 1000000)])''.join( (repr(i) for i in xrange(0, 1000000)) )
RedGlyph 2009年

8
ボビンスの結果は私にとって驚くべきことではありません。経験則として、Pythonの暗黙的なループは明示的なループよりも高速で、多くの場合劇的に高速です。mapCループを使用してCで実装されます。これは、仮想マシンで実行されるPythonループよりもはるかに高速です。
フェルディナンドベイヤー

7
驚くことではありませんが、リスト内包表記の評判(この例では30%のヒット)にはあまりにも悪いです。しかし、これが本当に重要でない限り、非常に高速なコードよりも明確にしたいので、ここでは大したことはありません。そうは言っても、map()関数は不明確であるように思われません。LCは過大評価されることがあります。
RedGlyph 2009年

4
map私には完全に明快で簡潔に思え、Pythonさえ知りません。
Zenexer 2013

1

私の推測では、それがあるnumメソッドを定義していない__str__()ので、str()ための第2のルックアップを行う必要があります__repr__

バックティックは直接探します__repr__。それが本当であればrepr()、バッククォートの代わりに使用しても同じ結果が得られるはずです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.