Python字典而不是switch / case

时间:2010-02-08 16:00:31

标签: python dictionary switch-statement

我最近了解到python没有switch / case语句。我一直在阅读有关使用字典的内容,例如:

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)()

我已尝试使用if / 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,'}'

检查var sep_ang的1500个值需要接近5分钟。好像我不想使用setAttribute()根据sep_ang的值更改我的xml文件中的值,我使用这个简单的if else:

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语句只检查单个值。

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

6 个答案:

答案 0 :(得分:10)

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

答案 1 :(得分:4)

虽然字典方法适用于单个值,但如果需要范围,if ... else if ... else if可能是最简单的方法。

如果你正在寻找单个值,这与字典很匹配 - 因为这是字典的用途 - 但是如果你正在寻找一个范围它不起作用。您可以使用dict使用以下内容执行此操作:

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

然后循环遍历字典中的所有键值对,传递值键并在键函数返回true时将值作为函数运行。

但是,这对于许多if语句没有任何好处,并且难以维护和调试。所以不要这样做,而只是使用if

答案 2 :(得分:3)

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

switch语句的想法是你有一个值V,你可以根据N个可能的结果来测试身份。您可以使用if-construct执行此操作 - 但是平均需要O(N)运行时。每次开关都会给你恒定的O(1)。

这显然不适用于范围(因为它们不易于清除),因此您对这些情况使用if-constructs。

实施例

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

请注意,这实际上比尝试使用字典要小。

答案 3 :(得分:2)

dict不是为了这样做(也不是切换!)。

有几张海报提出了一个带有遏制功能的字典,但这根本不是你想要的解决方案。它是O(n)(就像一个if语句),它不起作用(因为你可能有重叠的条件),是不可预测的(因为你不知道你将做什么顺序循环),并且不太明确比等价的if语句。 if语句可能是你想要的方式,如果你有一个短的,静态长度的条件列表来应用。

如果您有大量条件或者由于您的程序而可能会发生变化,那么您需要不同的数据结构。您可以实现二叉树或保留已排序的list并使用bisect模块查找与给定范围关联的值。

答案 4 :(得分:0)

我不知道任何切实可行的解决方案。如果你想使用猜测它做什么的方法,你可以这样做:

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

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

答案 5 :(得分:-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行代码一样快,我没有改变任何值的东西!