我想用Python编写一个函数,根据输入索引的值返回不同的固定值。

在其他语言中,我会使用switch或case语句,但Python似乎没有switch语句。在此场景中,推荐的Python解决方案是什么?


当前回答

我发现Python文档中的以下答案非常有用:

你可以通过一系列if…elif。。。埃利夫。。。其他的关于switch语句语法已经有了一些建议,但对于是否以及如何进行范围测试还没有达成共识。有关完整详细信息和当前状态,请参见PEP 275。

对于需要从大量可能性中进行选择的情况,可以创建一个字典,将大小写值映射到要调用的函数。例如:

def function_1(...):
    ...

functions = {'a': function_1,
             'b': function_2,
             'c': self.method_1, ...}

func = functions[value]
func()

对于在对象上调用方法,可以通过使用内置的getattr()来检索具有特定名称的方法来进一步简化:

def visit_a(self, ...):
    ...
...

def dispatch(self, value):
    method_name = 'visit_' + str(value)
    method = getattr(self, method_name)
    method()

建议为方法名称使用前缀,例如本例中的visit_。如果没有这样的前缀,如果值来自不受信任的源,攻击者将能够调用对象上的任何方法。

其他回答

还有另一种选择:

def fnc_MonthSwitch(int_Month): #### Define a function take in the month variable 
    str_Return ="Not Found"     #### Set Default Value 
    if int_Month==1:       str_Return = "Jan"   
    if int_Month==2:       str_Return = "Feb"   
    if int_Month==3:       str_Return = "Mar"   
    return str_Return;          #### Return the month found  
print ("Month Test 3:  " + fnc_MonthSwitch( 3) )
print ("Month Test 14: " + fnc_MonthSwitch(14) )

如果您真的只是返回一个预定的固定值,那么可以创建一个字典,其中包含所有可能的输入索引作为键,以及它们的对应值。此外,您可能真的不希望函数执行此操作,除非您以某种方式计算返回值。

哦,如果你想做一些类似开关的事情,请看这里。

定义:

def switch1(value, options):
  if value in options:
    options[value]()

允许您使用相当简单的语法,并将案例绑定到映射中:

def sample1(x):
  local = 'betty'
  switch1(x, {
    'a': lambda: print("hello"),
    'b': lambda: (
      print("goodbye," + local),
      print("!")),
    })

我一直试图用一种能让我摆脱“lambda:”的方式重新定义开关,但我放弃了。调整定义:

def switch(value, *maps):
  options = {}
  for m in maps:
    options.update(m)
  if value in options:
    options[value]()
  elif None in options:
    options[None]()

允许我将多个案例映射到同一代码,并提供默认选项:

def sample(x):
  switch(x, {
    _: lambda: print("other") 
    for _ in 'cdef'
    }, {
    'a': lambda: print("hello"),
    'b': lambda: (
      print("goodbye,"),
      print("!")),
    None: lambda: print("I dunno")
    })

每个复制的案例都必须在自己的字典中;switch()在查找值之前合并字典。它仍然比我想象的更丑,但它的基本效率是对表达式使用散列查找,而不是循环所有键。

Python>=3.10

哇,Python 3.10+现在有一个match/case语法,类似于switch/case等等!

PEP 634——结构模式匹配

匹配/案例的选定特征

1-匹配值:

匹配值类似于另一种语言中的简单开关/大小写:

match something:
    case 1 | 2 | 3:
        # Match 1-3.
    case _:
        # Anything else.
        # 
        # Match will throw an error if this is omitted 
        # and it doesn't match any of the other patterns.

2-匹配结构模式:

match something:
    case str() | bytes():  
        # Match a string like object.
    case [str(), int()]:
        # Match a `str` and an `int` sequence 
        # (`list` or a `tuple` but not a `set` or an iterator). 
    case [_, _]:
        # Match a sequence of 2 variables.
        # To prevent a common mistake, sequence patterns don’t match strings.
    case {"bandwidth": 100, "latency": 300}:
        # Match this dict. Extra keys are ignored.

3-捕获变量

解析对象;将其保存为变量:

match something:
    case [name, count]
        # Match a sequence of any two objects and parse them into the two variables.
    case [x, y, *rest]:
        # Match a sequence of two or more objects, 
        # binding object #3 and on into the rest variable.
    case bytes() | str() as text:
        # Match any string like object and save it to the text variable.

捕获变量在解析数据(如JSON或HTML)时非常有用,这些数据可能以多种不同的模式之一出现。

捕获变量是一项功能。但这也意味着您只需要使用虚线常量(例如:COLOR.RED)。否则,常量将被视为捕获变量并被覆盖。

更多示例用法:

match something:
    case 0 | 1 | 2:
        # Matches 0, 1 or 2 (value).
        print("Small number")
    case [] | [_]:
        # Matches an empty or single value sequence (structure).
        # Matches lists and tuples but not sets.
        print("A short sequence")
    case str() | bytes():
        # Something of `str` or `bytes` type (data type).
        print("Something string-like")
    case _:
        # Anything not matched by the above.
        print("Something else")

Python<=3.9

我最喜欢的switch/case Python配方是:

choices = {'a': 1, 'b': 2}
result = choices.get(key, 'default')

简单场景的简短和简单。

比较11行以上的C代码:

// C Language version of a simple 'switch/case'.
switch( key ) 
{
    case 'a' :
        result = 1;
        break;
    case 'b' :
        result = 2;
        break;
    default :
        result = -1;
}

您甚至可以通过使用元组来分配多个变量:

choices = {'a': (1, 2, 3), 'b': (4, 5, 6)}
(result1, result2, result3) = choices.get(key, ('default1', 'default2', 'default3'))

我做了一个switch-case实现,它在外部不太使用if(它仍然在类中使用if)。

class SwitchCase(object):
    def __init__(self):
        self._cases = dict()

    def add_case(self,value, fn):
        self._cases[value] = fn

    def add_default_case(self,fn):
        self._cases['default']  = fn

    def switch_case(self,value):
        if value in self._cases.keys():
            return self._cases[value](value)
        else:
            return self._cases['default'](0)

这样使用:

from switch_case import SwitchCase
switcher = SwitchCase()
switcher.add_case(1, lambda x:x+1)
switcher.add_case(2, lambda x:x+3)
switcher.add_default_case(lambda _:[1,2,3,4,5])

print switcher.switch_case(1) #2
print switcher.switch_case(2) #5
print switcher.switch_case(123) #[1, 2, 3, 4, 5]