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

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


当前回答

扩展Greg Hewgill的答案-我们可以使用装饰器封装字典解决方案:

def case(callable):
    """switch-case decorator"""
    class case_class(object):
        def __init__(self, *args, **kwargs):
            self.args = args
            self.kwargs = kwargs

        def do_call(self):
            return callable(*self.args, **self.kwargs)

return case_class

def switch(key, cases, default=None):
    """switch-statement"""
    ret = None
    try:
        ret = case[key].do_call()
    except KeyError:
        if default:
            ret = default.do_call()
    finally:
        return ret

然后可以将其与@case decorator一起使用

@case
def case_1(arg1):
    print 'case_1: ', arg1

@case
def case_2(arg1, arg2):
    print 'case_2'
    return arg1, arg2

@case
def default_case(arg1, arg2, arg3):
    print 'default_case: ', arg1, arg2, arg3

ret = switch(somearg, {
    1: case_1('somestring'),
    2: case_2(13, 42)
}, default_case(123, 'astring', 3.14))

print ret

好消息是,这已经在NeoPySwitch模块中完成。只需使用pip进行安装:

pip install NeoPySwitch

其他回答

如果你有一个复杂的大小写块,你可以考虑使用函数字典查找表。。。

如果您以前没有这样做过,那么最好进入调试器并查看字典如何查找每个函数。

注意:不要在大小写/字典查找中使用“()”,否则将在创建字典/大小写块时调用每个函数。记住这一点,因为您只想使用哈希样式查找调用每个函数一次。

def first_case():
    print "first"

def second_case():
    print "second"

def third_case():
    print "third"

mycase = {
'first': first_case, #do not use ()
'second': second_case, #do not use ()
'third': third_case #do not use ()
}
myfunc = mycase['first']
myfunc()

易于记忆:

while True:
    try:
        x = int(input("Enter a numerical input: "))
    except:
        print("Invalid input - please enter a Integer!");
    if x==1:
        print("good");
    elif x==2:
        print("bad");
    elif x==3:
        break
    else:
        print ("terrible");

定义:

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()在查找值之前合并字典。它仍然比我想象的更丑,但它的基本效率是对表达式使用散列查找,而不是循环所有键。

如果您不担心丢失案例套件中的语法高亮显示,可以执行以下操作:

exec {
    1: """
print ('one')
""", 
    2: """
print ('two')
""", 
    3: """
print ('three')
""",
}.get(value, """
print ('None')
""")

其中value是值。在C中,这将是:

switch (value) {
    case 1:
        printf("one");
        break;
    case 2:
        printf("two");
        break;
    case 3:
        printf("three");
        break;
    default:
        printf("None");
        break;
}

我们还可以创建一个helper函数来实现这一点:

def switch(value, cases, default):
    exec cases.get(value, default)

因此,我们可以将其用于一、二和三的示例:

switch(value, {
    1: """
print ('one')
    """, 
    2: """
print ('two')
    """, 
    3: """
print ('three')
    """,
}, """
print ('None')
""")

到目前为止,已经有很多回答说,“我们在Python中没有开关,这样做吧”。然而,我想指出,switch语句本身是一个容易被滥用的构造,在大多数情况下可以而且应该避免,因为它们促进了惰性编程。案例说明:

def ToUpper(lcChar):
    if (lcChar == 'a' or lcChar == 'A'):
        return 'A'
    elif (lcChar == 'b' or lcChar == 'B'):
        return 'B'
    ...
    elif (lcChar == 'z' or lcChar == 'Z'):
        return 'Z'
    else:
        return None        # or something

现在,您可以使用switch语句(如果Python提供了switch语句)来执行此操作,但这会浪费您的时间,因为有些方法可以很好地执行此操作。或者,你有一些不太明显的东西:

def ConvertToReason(code):
    if (code == 200):
        return 'Okay'
    elif (code == 400):
        return 'Bad Request'
    elif (code == 404):
        return 'Not Found'
    else:
        return None

然而,这种操作可以而且应该用字典来处理,因为它会更快、更复杂、更不容易出错和更紧凑。

switch语句的绝大多数“用例”将属于这两种情况之一;如果你彻底考虑了你的问题,就没有什么理由使用它。

因此,与其问“我如何在Python中切换?”,或许我们应该问“我为什么要在Python中进行切换?”因为这往往是一个更有趣的问题,而且往往会暴露出您正在构建的任何设计中的缺陷。

现在,这并不是说也不应该使用开关。状态机、词法分析器、解析器和自动机都在某种程度上使用它们,一般来说,当你从对称输入开始到非对称输出时,它们会很有用;您只需要确保不要将开关用作锤子,因为您在代码中看到了一堆钉子。