使用Python字典代替switch/case

3 投票
6 回答
8857 浏览
提问于 2025-04-15 19:01

我最近了解到,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,'}'

这段代码检查大约1500个变量sep_ang的值,差不多要花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 个回答

5

虽然字典这种方法对于单个值很有效,但如果你想处理范围的话,使用if ... else if ... else if可能是最简单的办法。

如果你只想找一个单一的值,字典是个不错的选择,因为字典就是用来做这个的。但如果你想处理一个范围,字典就不太适用了。你可以用dict来做,像这样:

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

然后你需要遍历字典里的所有键值对,传入你的值作为键,如果键对应的函数返回真,就执行这个值作为函数。

不过,这样做其实并没有比多个if语句更好,而且还会让维护和调试变得更困难。所以还是别这样做,直接用if就好了。

11

字典并不是解决这个问题的合适结构。bisect 的例子展示了如何进行这种范围测试的一个例子。

-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

这样不仅能正常运行,而且速度几乎和我原来的四行代码一样快,原来的代码里我没有改变任何值!

撰写回答