Python 写 switch case 的有效方式与比较

新手上路,请多包涵

我通常使用字典实现 switch/case 以进行相等比较。

 dict = {0:'zero', 1:'one', 2:'two'};
a=1; res = dict[a]

代替

if a == 0:
  res = 'zero'
elif a == 1:
  res = 'one'
elif a == 2:
  res = 'two'

是否有针对非平等比较实施类似方法的策略?

 if score <= 10:
  cat = 'A'
elif score > 10 and score <= 30:
  cat = 'B'
elif score > 30 and score <= 50:
  cat = 'C'
elif score > 50 and score <= 90:
  cat = 'D'
else:
  cat = 'E'

我知道使用 <、<=、>、>= 可能会很棘手,但是是否有任何策略可以概括它或从假设列表中生成自动语句

{[10]:'A', [10,30]:'B', [30,50]:'C',[50,90]:'D',[90]:'E'}

还有一些标志说它是 < 还是 <=

原文由 Kenny 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 416
1 个回答

字典可以包含很多值。如果您的范围不是太宽,您可以通过以编程方式扩展每个范围来制作一个类似于您为平等条件所拥有的字典:

 from collections import defaultdict

ranges   = {(0,10):'A', (10,30):'B', (30,50):'C',(50,90):'D'}
valueMap = defaultdict(lambda:'E')
for r,letter in ranges.items():
    valueMap.update({ v:letter for v in range(*r) })

valueMap[701] # 'E'
valueMap[7] # 'A'

您也可以从 if / elif 语句中删除多余的条件,并以不同的方式设置格式。这几乎看起来像一个案例陈述:

 if   score < 10 : cat = 'A'
elif score < 30 : cat = 'B'
elif score < 50 : cat = 'C'
elif score < 90 : cat = 'D'
else            : cat = 'E'

为避免重复 score < ,您可以定义一个 case 函数并将其与值一起使用:

 score = 43
case = lambda x: score < x
if   case(10): cat = "A"
elif case(30): cat = "B"
elif case(50): cat = "C"
elif case(90): cat = "D"
else         : cat = "E"
print (cat) # 'C'

您可以通过创建一个 switch 函数来概括这一点,该函数返回一个“案例”函数,该函数适用于具有通用比较模式的测试值:

 def switch(value):
    def case(check,lessThan=None):
        if lessThan is not None:
            return (check is None or check <= value) and value < lessThan
        if type(value) == type(check): return value == check
        if isinstance(value,type(case)): return check(value)
        return value in check
    return case

这个通用版本允许各种组合:

 score = 35
case = switch(score)
if   case(0,10)         : cat = "A"
elif case([10,11,12,13,14,15,16,17,18,19]):
                          cat = "B"
elif score < 30         : cat = "B"
elif case(30) \
  or case(range(31,50)) : cat = 'C'
elif case(50,90)        : cat = 'D'
else                    : cat = "E"
print(cat) # 'C'

当您需要做的只是返回一个值时,还有另一种使用 lambda 函数的方法:

 score = 41
case  = lambda x,v: v if score<x else None
cat   = case(10,'A') or case(20,'B') or case(30,'C') or case(50,'D') or 'E'
print(cat) # "D"

最后一个也可以使用列表理解和映射表来表示:

 mapping = [(10,'A'),(30,'B'),(50,'C'),(90,'D')]
scoreCat = lambda s: next( (L for x,L in mapping if s<x),"E" )

score = 37
cat = scoreCat(score)
print(cat) #"D"

更具体地说,可以使用根据您的参数返回映射函数的设置函数来创建通用解决方案:

 def rangeMap(*breaks,inclusive=False):
    default = breaks[-1] if len(breaks)&1 else None
    breaks  = list(zip(breaks[::2],breaks[1::2]))
    def mapValueLT(value):
        return next( (tag for tag,bound in breaks if value<bound), default)
    def mapValueLE(value):
        return next( (tag for tag,bound in breaks if value<=bound), default)
    return mapValueLE if inclusive else mapValueLT

scoreToCategory = rangeMap('A',10,'B',30,'C',50,'D',90,'E')

print(scoreToCategory(53)) # D
print(scoreToCategory(30)) # C

scoreToCategoryLE = rangeMap('A',10,'B',30,'C',50,'D',90,'E',inclusive=True)

print(scoreToCategoryLE(30)) # B

请注意,通过多做一些工作,您可以使用bisect模块提高返回函数的性能。

原文由 Alain T. 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题