2010-02-08 82 views
2

我最近才知道python没有switch/case语句。我一直在阅读有关使用字典代替它,像这样的例子:Python字典代替开关/外壳

values = { 
    value1: do_some_stuff1, 
    value2: do_some_stuff2, 
    valueN: do_some_stuffN, 
} 
values.get(var, do_default_stuff)() 

我想不通的是如何应用此做了一系列的测试。因此,而不是做一些东西,如果value1=4说,做了一些东西,如果value1<4.因此,像这样(我知道不工作)的:

values = { 
    if value1 <val: do_some_stuff1, 
    if value2 >val: do_some_stuff2, 
} 
values.get(var, do_default_stuff)() 

我试着如果/ elif的/ else语句这样做。它工作正常,但它似乎比我根本不需要if语句的情况要慢得多(这可能是明显不可避免的)。因此,这里是我的代码与if/elif的/ else语句:

if sep_ang(val1,val2,X,Y)>=ROI : 
    main.removeChild(source) 
elif sep_ang(val1,val2,X,Y)<=5.0: 
    integral=float(spectrum[0].getElementsByTagName("parameter")[0].getAttribute("free")) 
    index=float(spectrum[0].getElementsByTagName("parameter")[0].getAttribute("free"))    
    print name,val1,val2,sep_ang(val1,val2,X,Y),integral,index 
    print >> reg,'fk5;point(',val1,val2,')# point=cross text={',name,'}' 
else: 
    spectrum[0].getElementsByTagName("parameter")[0].setAttribute("free","0") #Integral 
    spectrum[0].getElementsByTagName("parameter")[1].setAttribute("free","0") #Index 
    integral=float(spectrum[0].getElementsByTagName("parameter")[0].getAttribute("free")) 
    index=float(spectrum[0].getElementsByTagName("parameter")[0].getAttribute("free")) 
    print name,val1,val2,sep_ang(val1,val2,X,Y),integral,index 
    print >> reg,'fk5;point(',val1,val2,')# point=cross text={',name,'}' 

这需要接近5分钟检查约1500 VAR sep_ang的值。在哪里,如果我不希望使用的setAttribute()来改变基于sep_ang的价值我的XML文件中的值,我用这个,如果其他简单:

if sep_ang(val1,val2,X,Y)>=ROI : 
    main.removeChild(source) 
else: 
    print name,val1,val2,ang_sep(val1,val2,X,Y);print >> reg,'fk5;point(',val1,val2,')# point 

其中仅需要30秒〜。我再次明白,添加elif语句和更改该属性的值可能会不可避免地增加我的代码的执行时间,我只是很好奇它是否有解决方法。

编辑: 在我的情况下,使用bisect而不是if/elif语句的好处是,它可以比使用一堆elif语句更快地检查某个范围内的值吗?

看来我仍然需要使用elif语句。像这样,例如:

range=[10,100] 
options='abc' 
def func(val) 
    return options[bisect(range, val)] 
if func(val)=a: 
    do stuff 
elif func(val)=b: 
    do other stuff 
else: 
    do other other stuff 

那么,我的elif语句只是检查一个单一的值。

非常感谢您的帮助,非常感谢。

+0

您是否将14行代码与四行代码进行比较?你问为什么14行代码可能比4行代码慢? – 2010-02-08 18:57:17

+0

当然我知道14行代码的运行时间比4行代码的运行时间要长(这就是为什么我说它可能是显而易见且不可避免的,它运行得更慢)。我认为这不仅仅是因为一些代码比另一个代码多了10行,它应该慢10倍。我认为用我的代码大大减缓它的事情是,每个elif语句都必须检查我的ang_sep变量的1500左右的值。我知道我的代码会比elifs慢,我只是好奇,如果我做的事情效率低下,或者有更好的方法去做。 – Jamie 2010-02-08 21:20:35

回答

-2

终于想出了该怎么做!的

因此,而不是使用大量的elif语句我这样做:

range=[10,100] 
options='abc' 
def func(val) 
    choose=str(options[bisect(range,val)]) 
    exec choose+"()" 
def a(): 
     do_stuff 
def b(): 
     do_other_stuff 
def c(): 
     do_other_other stuff 

它不仅可以工作,但它会几乎一样快,在那里我不会改变任何值,我原来的4行代码事情!

+2

使用函数列表,而不是'exec'。 – 2010-02-09 15:57:07

+0

这不是很好的做法。 'exec'是邪恶的。 – 2012-10-19 19:41:40

3

在这种情况下,您将使用if/then/else。你也不能用开关来做到这一点。

switch语句的思想是,您有一个值V,您可以根据N个可能的结果测试身份。你可以用一个if结构来做到这一点 - 然而,平均需要O(N)运行时。开关每次给你恒定的O(1)。

这显然是不可能的范围(因为他们不容易哈脱),因此你使用if-constructs这些情况。

if value1 <val: do_some_stuff1() 
elif value2 >val: do_some_stuff2() 

注意,这实际上是比试图使用字典小。

+0

问题不在于范围很难散列,它不知道在字典中只有一个值时要查找哪个范围。 – 2010-02-08 17:14:03

+0

您可能希望查看局部敏感散列。这就是我写“难”而不是“不可能”的原因。 – bayer 2010-02-08 17:22:17

+0

LSH不能解决这个问题。 – 2010-02-08 17:39:56

4

尽管字典方法对于单个值的效果很好,但如果您需要范围,if ... else if ... else if可能是最简单的方法。

如果你正在寻找一个单一的值,这是一个很好的匹配字典 - 因为这是字典的目的 - 但如果你正在寻找一个范围它不起作用。

values = { 
    lambda x: x < 4: foo, 
    lambda x: x > 4: bar 
} 

,然后遍历字典中的所有键值对,传递你的价值的关键和运行值的函数,如果关键函数返回true:你可以使用类似与dict做到这一点。

但是,这并不会给您带来任何益处,因为它会对多个if语句产生任何影响,并且难以维护和调试。所以不要这样做,只需要使用if

+2

我同意,尽管这是可能的,但这不是正确的解决方案。只需使用一系列if/else语句。代码将更容易理解和维护。 – 2010-02-08 16:14:34

10

字典是错误的结构。 bisect examples展示了这种范围测试的一个例子。

0

我不知道任何可行的解决方案。如果你想要去的猜它做什么方法虽然你可以做这样的事情:(!也不是切换)

obsure_switch = { 
    lambda x: 1<x<6 : some_function, 
    ... 
} 

[action() for condition,action in obscure_switch.iteritems() if condition(var)] 
+2

这完全违背了使用字典获得O(1)的想法。 – bayer 2010-02-08 16:16:46

2

dict是不是这样做的。

一对海报提出了一个包含遏制功能的字典,但这不是您想要的解决方案。它是O(n)(就像if语句),它并不真正起作用(因为你可能有重叠的条件),是不可预知的(因为你不知道按照什么顺序进行循环),并且不太清楚比相当的if语句。 if语句可能是你想要的方式,如果你有一个简短的静态长度的条件列表来应用。

如果您有很多条件或者如果它们可能因程序而改变,您需要一个不同的数据结构。您可以实现二叉树或保留排序的list并使用bisect模块查找与给定范围相关的值。