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

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


当前回答

到目前为止,已经有很多回答说,“我们在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中进行切换?”因为这往往是一个更有趣的问题,而且往往会暴露出您正在构建的任何设计中的缺陷。

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

其他回答

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

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

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

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

还有另一种选择:

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

我从Twisted Python代码中学到了一种模式。

class SMTP:
    def lookupMethod(self, command):
        return getattr(self, 'do_' + command.upper(), None)
    def do_HELO(self, rest):
        return 'Howdy ' + rest
    def do_QUIT(self, rest):
        return 'Bye'

SMTP().lookupMethod('HELO')('foo.bar.com') # => 'Howdy foo.bar.com'
SMTP().lookupMethod('QUIT')('') # => 'Bye'

您可以在需要调度令牌和执行扩展代码段的任何时候使用它。在状态机中,您将有state_方法,并在self.state上分派。通过从基类继承并定义自己的do_方法,可以清晰地扩展此开关。通常,基类中甚至没有do_方法。

编辑:具体是如何使用的

如果是SMTP,您将收到来自网络的HELO。相关代码(来自twisted/mail/smtp.py,根据我们的情况进行了修改)如下

class SMTP:
    # ...

    def do_UNKNOWN(self, rest):
        raise NotImplementedError, 'received unknown command'

    def state_COMMAND(self, line):
        line = line.strip()
        parts = line.split(None, 1)
        if parts:
            method = self.lookupMethod(parts[0]) or self.do_UNKNOWN
            if len(parts) == 2:
                return method(parts[1])
            else:
                return method('')
        else:
            raise SyntaxError, 'bad syntax'

SMTP().state_COMMAND('   HELO   foo.bar.com  ') # => Howdy foo.bar.com

您将收到“HELO foo.bar.com”(或者您可能会收到“QUIT”或“RCPT TO:foo”)。这被标记为['HELO','foo.bar.com']。实际的方法查找名称取自部件[0]。

(原始方法也称为state_COMMAND,因为它使用相同的模式来实现状态机,即getattr(self,'state_'+self.mode))

仅仅将一些键映射到一些代码并不是一个真正的问题,正如大多数人在使用字典时所展示的那样。真正的诀窍是尝试模仿整个直通和中断过程。我认为我从来没有写过一个案例陈述,其中我使用了“功能”。这里有一个直通车。

def case(list): reduce(lambda b, f: (b | f[0], {False:(lambda:None),True:f[1]}[b | f[0]]())[0], list, False)

case([
    (False, lambda:print(5)),
    (True, lambda:print(4))
])

我真的把它想象成一个单独的陈述。我希望你能原谅这种愚蠢的格式。

reduce(
    initializer=False,
    function=(lambda b, f:
        ( b | f[0]
        , { False: (lambda:None)
          , True : f[1]
          }[b | f[0]]()
        )[0]
    ),
    iterable=[
        (False, lambda:print(5)),
        (True, lambda:print(4))
    ]
)

我希望这是有效的Python代码。它应该能让你通过。当然,布尔检查可以是表达式,如果您希望它们被延迟求值,那么可以将它们全部封装在lambda中。在执行了列表中的一些项目之后,也不难让它被接受。只需创建元组(bool,bool,function),其中第二个bool指示是否突破或放弃。

当我需要一个简单的switchcase来调用一堆方法而不仅仅是打印一些文本时,下面的方法适用于我的情况。在玩了lambda和globals之后,我觉得这是迄今为止最简单的选择。也许它也会帮助某人:

def start():
    print("Start")

def stop():
    print("Stop")

def print_help():
    print("Help")

def choose_action(arg):
    return {
        "start": start,
        "stop": stop,
        "help": print_help,
    }.get(arg, print_help)

argument = sys.argv[1].strip()
choose_action(argument)()  # calling a method from the given string