Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/351.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
一种有效的python值映射方法?_Python - Fatal编程技术网

一种有效的python值映射方法?

一种有效的python值映射方法?,python,Python,我有一些值需要重新映射,因为有两种方法可以指定规则。简单的if/else方法似乎更有效,但我想知道是否有一种同样有效但更具python风格的方法 if mod == "I": mod = "+" elif mod == "E": mod = "-" elif mod == "D": mod = ":" elif mod == "M": mod = "." 不太有效的映射方法: mod = { "I":"+", "E":"-", "D":":", "M":"." }.get(mod,

我有一些值需要重新映射,因为有两种方法可以指定规则。简单的
if
/
else
方法似乎更有效,但我想知道是否有一种同样有效但更具python风格的方法

 if mod == "I": mod = "+"
 elif mod == "E": mod = "-"
 elif mod == "D": mod = ":"
 elif mod == "M": mod = "."
不太有效的映射方法:

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

映射将导致O(1)查找。条件句将导致O(N)。当然,如果你想对它吹毛求疵的话,在你的map实现中还需要考虑额外的函数调用

而不是理论化。结果(删除
get
调用并严格使用数组访问器,结果:

   2 function calls in 0.025 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.025    0.025    0.025    0.025 {range}


   4 function calls in 0.035 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        2    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        2    0.035    0.018    0.035    0.018 {range}
if_else took 12474 ms for 100000 operations
translation_table took 81650 ms for 100000 operations
dict_lookup took 66385 ms for 100000 operations

现在不可否认,这只使用给定的案例。我的假设是,如果条件的运行时间将随着案例数量的增加而线性增加,而映射查找将保持不变。

如果案例数量固定且较少,那么
if else
方法是最快的(我不明白为什么它是非Pythonic的);对于足够多的情况,使用
dict
查找会更好

如果案例集是动态的,那么
dict
方法当然是唯一可行的方法

另外,第三种非正统的方法是使用宏元编程。这在vanilla python中是不可能的,但是有一些库允许您以(可以说)干净的方式(很可能未经python社区或Guido批准)完成这项工作


再想一想,在大多数Python宏实现中,宏方法在Python中可能不会像在Lisp中那样起作用,因为大多数Python宏实现都试图遵循普通Python的语法;即,如果无法从宏中生成elif else块,则无法在Python中生成

字符串方法具有转换功能n可用。您必须构建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)
输出:

-+:.

请记住,多级
if
语句会生成大量字节码,主要在Python级别进行评估,而字典访问则发生在解释器的优化C代码中。此外,如果存在
n
可能性,则
if
语句需要平均进行
n/2
比较:它必须按顺序检查每种可能性

这个故事的寓意是:
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

这并不是一个真正的答案,但很多评论都集中在性能上,因为我确实问过。因此,到目前为止,我对答案进行了一些性能测试:

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)
结果如下:

   2 function calls in 0.025 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.025    0.025    0.025    0.025 {range}


   4 function calls in 0.035 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        2    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        2    0.035    0.018    0.035    0.018 {range}
if_else took 12474 ms for 100000 operations
translation_table took 81650 ms for 100000 operations
dict_lookup took 66385 ms for 100000 operations

在什么意义上是有效的?你提出的方法有什么低效的地方(这是一个很好的Pythonic)?我同意Thijs的观点:如果你将dict存储为一个单独的引用,你只需要构造它一次并从此开始使用它。我想说这两种方法都是同样的pythonic。我感觉到过早的优化。Python的
dict
速度太快了。如果你提到的东西真的很重要(度量!),Python可能不是这项工作的工具。这不是一种在Python上计时的好方法。看看
timeit
。我发现
dict
if_else
的性能大致相同,这取决于if_else
输入的“运气”
if_else
的多少。到目前为止,我能找到的最快的东西是:
translate\u mod={“I:“+”,“E:“-”,“D:”,“M:”}.get
,然后可调用。它的性能始终比
if_else
好15%。它更快的原因是,您的一次查找(点)更少,当然
dict
只创建了一次。条件语句如何产生
O(N)以外的结果“为什么你说的是最坏的情况?我知道,地图的解决方案只是一个例子,我认为这是一个更大的pythic。我实际上不是问我提供的两个解决方案中哪一个是最好的选择。”Kjjro:猜测这是一个多余的,固定的。。您尝试了第一件事,结果是正确的。@cWallenPole:不过,可以说,O表示法应该反映算法的最坏情况复杂性。因此,O(N)是条件版本的运行时间。
from string import maketrans;translation_table=maketrans('IEDM','+-:。)
-我没有想到,但这确实是一个非常合理的解决方案。不过,我不确定它在引擎盖下如何工作;可能不会比一个
dict
快。让我运行一些计时,我会让你知道。
如果10万次操作需要12474毫秒,翻译表需要81650毫秒,10万次操作需要66385毫秒0000次操作
这不是在Python上计时的好方法。请看一下
timeit
@Craig:查看IPython及其
timeit
命令。