-1

ルールを指定するには 2 つの方法があることに基づいて、再マップする値がいくつかあります。シンプルなif/elseメソッドはより効率的なバリアントのように見えますが、同等に効率的でより Pythonic なアプローチがあるのだろうか?

 if mod == "I": mod = "+"
 elif mod == "E": mod = "-"
 elif mod == "D": mod = ":"
 elif mod == "M": mod = "."

あまり効率的でないマッピング アプローチ:

 mod = { "I":"+", "E":"-", "D":":", "M":"." }.get(mod, mod)
4

5 に答える 5

1

固定された少数のケースがある場合、if-elif-elseアプローチは最速です(そして、なぜそれが非Pythonicになるのかわかりません)。ケースの数が十分に多い場合は、dictルックアップの方が適切です。

ケースのセットが動的である場合、dictアプローチはもちろん唯一の実行可能なものです。

また、3 番目の非正統的なアプローチは、マクロ メタプログラミングを使用することです。これはバニラの python では不可能ですが、https ://github.com/lihaoyi/macropy などのライブラリがあり、(ほぼ間違いなく) クリーンな方法でこれを行うことができます (ほとんどの場合、Python コミュニティまたは Guido によって承認されていません)。

PS よく考えてみると、Python のほとんどのマクロ実装の場合、Lisp のように Python でマクロ アプローチが機能しない可能性があります。これは、バニラ Python の構文に固執しようとします。つまりif-elif-else、マクロ内からブロックを生成することはできません。

于 2013-10-18T20:12:35.837 に答える
1

マルチレベルifステートメントは大量のバイト コードを生成し、主に Python レベルで評価されますが、辞書アクセスはインタープリターの最適化された C コードで発生することに注意してください。また、可能性がある場合、ステートメントは比較ifの平均を必要とします。各可能性を順番にチェックする必要があります。n/2n

話の教訓:dictsおそらく十分に高速ですが、疑わしい場合はプロファイルを作成して、疑うものではなく、実際のボトルネックを見つけてください。


比較:

def f(mod):
    if mod == "I": return "+"
    elif mod == "E": return "-"
    elif mod == "D": return ":"
    elif mod == "M": return "."

dis.dis(f)
  4           0 LOAD_FAST                0 (mod)
              3 LOAD_CONST               1 ('I')
              6 COMPARE_OP               2 (==)
              9 POP_JUMP_IF_FALSE       16
             12 LOAD_CONST               2 ('+')
             15 RETURN_VALUE

  5     >>   16 LOAD_FAST                0 (mod)
             19 LOAD_CONST               3 ('E')
             22 COMPARE_OP               2 (==)
             25 POP_JUMP_IF_FALSE       32
             28 LOAD_CONST               4 ('-')
             31 RETURN_VALUE

  6     >>   32 LOAD_FAST                0 (mod)
             35 LOAD_CONST               5 ('D')
             38 COMPARE_OP               2 (==)
             41 POP_JUMP_IF_FALSE       48
             44 LOAD_CONST               6 (':')
             47 RETURN_VALUE

  7     >>   48 LOAD_FAST                0 (mod)
             51 LOAD_CONST               7 ('M')
             54 COMPARE_OP               2 (==)
             57 POP_JUMP_IF_FALSE       64
             60 LOAD_CONST               8 ('.')
             63 RETURN_VALUE
        >>   64 LOAD_CONST               0 (None)
             67 RETURN_VALUE


d={"I": "+", "E": "-", "D": ":", "M": "."}
def g(mod):
    return d.get(mod, mod)

12           0 LOAD_GLOBAL              0 (d)
             3 LOAD_ATTR                1 (get)
             6 LOAD_FAST                0 (mod)
             9 LOAD_FAST                0 (mod)
            12 CALL_FUNCTION            2
            15 RETURN_VALUE
于 2013-10-18T20:41:25.167 に答える
0

文字列メソッドには翻訳機能があります。256 文字の長さの変換テーブルを作成する必要があります。私が使用したコードスニペットは次のとおりです。

translationTable = ' '*256
translationTable = translationTable[:68]+':'+translationTable[69:] # D to :
translationTable = translationTable[:69]+'-'+translationTable[70:] # E to -
translationTable = translationTable[:73]+'+'+translationTable[74:] # I to +
translationTable = translationTable[:77]+'.'+translationTable[78:] # M to .
print 'EIDM'.translate(translationTable)

出力:

-+:.
于 2013-10-18T20:18:43.327 に答える
0

それ自体はそれほど答えではありませんが、私が尋ねたので、多くのコメントがパフォーマンスに集中していました。そこで、これまでの回答に対していくつかのパフォーマンス テストを実行しました。

from datetime import datetime
from string import maketrans
tr_table = maketrans('IEDM', '+-:.')
dictionary = { "I":"+", "E":"-", "D":":", "M":"." }
if_else_val = "E"

N_OPS = 100000

now = datetime.now

def time(func):
    s = now()
    func()
    print "%s took %d ms for %d operations" % (func.__name__, (now() - s).microseconds, N_OPS)

def translation_table():
    for i in xrange(N_OPS):
        "I".translate(tr_table)
        "E".translate(tr_table)
        "D".translate(tr_table)
        "M".translate(tr_table)

def dict_lookup():
    for i in xrange(N_OPS):
        dictionary.get("I")
        dictionary.get("E")
        dictionary.get("D")
        dictionary.get("M")

def if_else():
    for i in xrange(N_OPS):
        if if_else_val == "I": pass
        elif if_else_val == "E": pass
        elif if_else_val == "D": pass
        elif if_else_val == "M": pass

time(if_else)
time(translation_table)
time(dict_lookup)

結果は次のとおりです。

if_else took 12474 ms for 100000 operations
translation_table took 81650 ms for 100000 operations
dict_lookup took 66385 ms for 100000 operations
于 2013-10-18T21:03:19.107 に答える