Python中的switch语句的替换?

时间:2008-09-13 00:36:31

标签: python switch-statement

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

在其他语言中,我会使用switchcase语句,但Python似乎没有switch语句。在这种情况下,推荐的Python解决方案是什么?

44 个答案:

答案 0 :(得分:1340)

你可以使用字典:

def f(x):
    return {
        'a': 1,
        'b': 2,
    }[x]

答案 1 :(得分:1257)

如果您想要默认设置,可以使用字典get(key[, default])方法:

def f(x):
    return {
        'a': 1,
        'b': 2
    }.get(x, 9)    # 9 is default if x not found

答案 2 :(得分:353)

我一直喜欢这样做

result = {
  'a': lambda x: x * 5,
  'b': lambda x: x + 7,
  'c': lambda x: x - 2
}[value](x)

From here

答案 3 :(得分:299)

除了字典方法(我非常喜欢BTW)之外,您还可以使用if-elif-else来获取开关/案例/默认功能:

if x == 'a':
    # Do the thing
elif x == 'b':
    # Do the other thing
if x in 'bc':
    # Fall-through by not using elif, but now the default case includes case 'a'!
elif x in 'xyz':
    # Do yet another thing
else:
    # Do the default

这当然与开关/箱子不一样 - 你不能像离开休息那样容易穿透;声明,但你可以进行更复杂的测试。它的格式比一系列嵌套ifs更好,即使功能上它更接近它。

答案 4 :(得分:158)

我最喜欢的开关/案例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'))

答案 5 :(得分:96)

class switch(object):
    value = None
    def __new__(class_, value):
        class_.value = value
        return True

def case(*args):
    return any((arg == switch.value for arg in args))

用法:

while switch(n):
    if case(0):
        print "You typed zero."
        break
    if case(1, 4, 9):
        print "n is a perfect square."
        break
    if case(2):
        print "n is an even number."
    if case(2, 3, 5, 7):
        print "n is a prime number."
        break
    if case(6, 8):
        print "n is an even number."
        break
    print "Only single-digit numbers are allowed."
    break

试验:

n = 2
#Result:
#n is an even number.
#n is a prime number.
n = 11
#Result:
#Only single-digit numbers are allowed.

答案 6 :(得分:45)

我从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')。这被标记为parts ['HELO', 'foo.bar.com']。实际的方法查找名称取自parts[0]

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

答案 7 :(得分:43)

我最喜欢的是一个非常好的recipe。你真的很喜欢它。它是我见过的最接近实际的switch case语句,特别是在功能中。

class switch(object):
    def __init__(self, value):
        self.value = value
        self.fall = False

    def __iter__(self):
        """Return the match method once, then stop"""
        yield self.match
        raise StopIteration

    def match(self, *args):
        """Indicate whether or not to enter a case suite"""
        if self.fall or not args:
            return True
        elif self.value in args: # changed for v1.5, see below
            self.fall = True
            return True
        else:
            return False

以下是一个例子:

# The following example is pretty much the exact use-case of a dictionary,
# but is included for its simplicity. Note that you can include statements
# in each suite.
v = 'ten'
for case in switch(v):
    if case('one'):
        print 1
        break
    if case('two'):
        print 2
        break
    if case('ten'):
        print 10
        break
    if case('eleven'):
        print 11
        break
    if case(): # default, could also just omit condition or 'if True'
        print "something else!"
        # No need to break here, it'll stop anyway

# break is used here to look as much like the real thing as possible, but
# elif is generally just as good and more concise.

# Empty suites are considered syntax errors, so intentional fall-throughs
# should contain 'pass'
c = 'z'
for case in switch(c):
    if case('a'): pass # only necessary if the rest of the suite is empty
    if case('b'): pass
    # ...
    if case('y'): pass
    if case('z'):
        print "c is lowercase!"
        break
    if case('A'): pass
    # ...
    if case('Z'):
        print "c is uppercase!"
        break
    if case(): # default
        print "I dunno what c was!"

# As suggested by Pierre Quentel, you can even expand upon the
# functionality of the classic 'case' statement by matching multiple
# cases in a single shot. This greatly benefits operations such as the
# uppercase/lowercase example above:
import string
c = 'A'
for case in switch(c):
    if case(*string.lowercase): # note the * for unpacking as arguments
        print "c is lowercase!"
        break
    if case(*string.uppercase):
        print "c is uppercase!"
        break
    if case('!', '?', '.'): # normal argument passing style also applies
        print "c is a sentence terminator!"
        break
    if case(): # default
        print "I dunno what c was!"

答案 8 :(得分:40)

class Switch:
    def __init__(self, value):
        self.value = value

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        return False # Allows a traceback to occur

    def __call__(self, *values):
        return self.value in values


from datetime import datetime

with Switch(datetime.today().weekday()) as case:
    if case(0):
        # Basic usage of switch
        print("I hate mondays so much.")
        # Note there is no break needed here
    elif case(1,2):
        # This switch also supports multiple conditions (in one line)
        print("When is the weekend going to be here?")
    elif case(3,4):
        print("The weekend is near.")
    else:
        # Default would occur here
        print("Let's go have fun!") # Didn't use case for example purposes

答案 9 :(得分:24)

假设你不想只返回一个值,而是希望使用改变对象上某些东西的方法。使用这里陈述的方法将是:

result = {
  'a': obj.increment(x),
  'b': obj.decrement(x)
}.get(value, obj.default(x))

这里发生的是python评估字典中的所有方法。 因此,即使您的值为'a',对象也会递增递减x。

解决方案:

func, args = {
  'a' : (obj.increment, (x,)),
  'b' : (obj.decrement, (x,)),
}.get(value, (obj.default, (x,)))

result = func(*args)

所以你得到一个包含函数及其参数的列表。这样,只返回函数指针和参数列表,计算。 'result'然后计算返回的函数调用。

答案 10 :(得分:18)

我只想把我的两分钱放在这里。 Python中没有case / switch语句的原因是因为Python遵循的原则是Theres只有一种正确的方法来做某事'。很明显,你可以想出各种方法来重新创建开关/案例功能,但Pythonic实现这一点的方法是if / elif结构。即

if something:
    return "first thing"
elif somethingelse:
    return "second thing"
elif yetanotherthing:
    return "third thing"
else:
    return "default thing"

我觉得PEP 8值得点头。 Python的一个美妙之处在于其简洁和优雅。这很大程度上源于我们在PEP 8中提出的原则,包括"只有一种正确的方法可以做某事"

答案 11 :(得分:16)

扩大“dict as switch”的想法。如果您想使用交换机的默认值:

def f(x):
    try:
        return {
            'a': 1,
            'b': 2,
        }[x]
    except KeyError:
        return 'default'

答案 12 :(得分:15)

如果您正在搜索extra-statement,作为“switch”,我构建了一个扩展Python的python模块。它被称为ESPY为“Python的增强结构”,它可用于Python 2.x和Python 3.x.

例如,在这种情况下,可以通过以下代码执行switch语句:

macro switch(arg1):
    while True:
        cont=False
        val=%arg1%
        socket case(arg2):
            if val==%arg2% or cont:
                cont=True
                socket
        socket else:
            socket
        break

可以像这样使用:

a=3
switch(a):
    case(0):
        print("Zero")
    case(1):
        print("Smaller than 2"):
        break
    else:
        print ("greater than 1")

所以espy将它在Python中翻译为:

a=3
while True:
    cont=False
    if a==0 or cont:
        cont=True
        print ("Zero")
    if a==1 or cont:
        cont=True
        print ("Smaller than 2")
        break
    print ("greater than 1")
    break

答案 13 :(得分:15)

如果您有一个复杂的案例块,您可以考虑使用函数字典查找表...

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

注意:在案例/字典查找中使用“()”,或者在创建字典/案例块时调用每个函数。请记住这一点,因为您只想使用哈希样式查找来调用每个函数一次。

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

答案 14 :(得分:13)

我没有在谷歌搜索的任何地方找到我想要的简单答案。但无论如何我都想通了。这真的很简单。决定张贴它,也许可以防止别人头上的一些划痕。关键是“in”和元组。这是带有连贯的switch语句行为,包括RANDOM直通。

l = ['Dog', 'Cat', 'Bird', 'Bigfoot',
     'Dragonfly', 'Snake', 'Bat', 'Loch Ness Monster']

for x in l:
    if x in ('Dog', 'Cat'):
        x += " has four legs"
    elif x in ('Bat', 'Bird', 'Dragonfly'):
        x += " has wings."
    elif x in ('Snake',):
        x += " has a forked tongue."
    else:
        x += " is a big mystery by default."
    print(x)

print()

for x in range(10):
    if x in (0, 1):
        x = "Values 0 and 1 caught here."
    elif x in (2,):
        x = "Value 2 caught here."
    elif x in (3, 7, 8):
        x = "Values 3, 7, 8 caught here."
    elif x in (4, 6):
        x = "Values 4 and 6 caught here"
    else:
        x = "Values 5 and 9 caught in default."
    print(x)

提供:

Dog has four legs
Cat has four legs
Bird has wings.
Bigfoot is a big mystery by default.
Dragonfly has wings.
Snake has a forked tongue.
Bat has wings.
Loch Ness Monster is a big mystery by default.

Values 0 and 1 caught here.
Values 0 and 1 caught here.
Value 2 caught here.
Values 3, 7, 8 caught here.
Values 4 and 6 caught here
Values 5 and 9 caught in default.
Values 4 and 6 caught here
Values 3, 7, 8 caught here.
Values 3, 7, 8 caught here.
Values 5 and 9 caught in default.

答案 15 :(得分:13)

我发现了一个常见的开关结构:

switch ...parameter...
case p1: v1; break;
case p2: v2; break;
default: v3;

可以用Python表示如下:

(lambda x: v1 if p1(x) else v2 if p2(x) else v3)

或以更清晰的方式格式化:

(lambda x:
     v1 if p1(x) else
     v2 if p2(x) else
     v3)

python版本不是一个语句,而是一个表达式,它的计算结果为值。

答案 16 :(得分:11)

我使用的解决方案:

这里发布的两个解决方案的组合,相对容易阅读并支持默认值。

result = {
  'a': lambda x: x * 5,
  'b': lambda x: x + 7,
  'c': lambda x: x - 2
}.get(whatToUse, lambda x: x - 22)(value)

,其中

.get('c', lambda x: x - 22)(23)

在dict中查找"lambda x: x - 2"并将其与x=23

一起使用
.get('xxx', lambda x: x - 22)(44)

在dict中找不到它,并使用默认"lambda x: x - 22"x=44

答案 17 :(得分:10)

这里的大部分答案都很旧,尤其是已接受的答案,所以看起来值得更新。

首先,官方Python FAQ涵盖了这一点,并针对简单案例推荐elif链,针对更大或更复杂的案例推荐dict。它还为某些情况建议了一组visit_方法(许多服务器框架使用的样式):

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

FAQ还提到PEP 275,这是为了获得关于添加C风格切换语句的官方一劳永逸的决定而编写的。但是,PEP实际上被推迟到Python 3,它只是作为一个单独的提案被正式拒绝,PEP 3103。答案当然是否定的,但如果您对原因或历史感兴趣,那么两位PEP可以链接到其他信息。

多次出现的一件事(可以在PEP 275中看到,即使它被作为实际建议被删除)是,如果你真的被8行代码来处理4个案件而烦恼,相对于你在C或Bash中拥有的6行,你总是可以这样写:

if x == 1: print('first')
elif x == 2: print('second')
elif x == 3: print('third')
else: print('did not place')

PEP 8并没有完全鼓励这一点,但它的可读性并不太单一。

自PEP 3103被拒绝十多年以来,C风格的案例陈述问题,甚至是Go中稍微强大的版本,都被认为是死的;每当有人提出python-ideas或-dev时,他们就会提到旧决定。

然而,每隔几年就会出现完全ML风格模式匹配的想法,特别是因为像Swift和Rust这样的语言已经采用了它。问题在于,如果没有代数数据类型,很难在模式匹配中得到充分利用。虽然Guido一直对这个想法表示同情,但没有人能够提出一个非常适合Python的提案。 (您可以阅读my 2014 strawman作为示例。)这可能会随着3.7中的dataclass和一些更强大的enum来处理和类型或者针对不同类型的各种提案的零星提议而改变语句本地绑定(如PEP 3150,或当前正在讨论的提议集)。但到目前为止,它还没有。

对于Perl 6风格的匹配,偶尔也会提出建议,这基本上是从elif到正则表达式到单一调度类型切换的所有内容的混搭。

答案 18 :(得分:10)

def f(x):
    dictionary = {'a':1, 'b':2, 'c':3}
    return dictionary.get(x,'Not Found') 
##Returns the value for the letter x;returns 'Not Found' if x isn't a key in the dictionary

答案 19 :(得分:9)

# simple case alternative

some_value = 5.0

# this while loop block simulates a case block

# case
while True:

    # case 1
    if some_value > 5:
        print ('Greater than five')
        break

    # case 2
    if some_value == 5:
        print ('Equal to five')
        break

    # else case 3
    print ( 'Must be less than 5')
    break

答案 20 :(得分:7)

我喜欢Mark Bies's answer

由于x变量必须使用两次,我将lambda函数修改为无参数。

我必须使用results[value](value)

运行
In [2]: result = {
    ...:   'a': lambda x: 'A',
    ...:   'b': lambda x: 'B',
    ...:   'c': lambda x: 'C'
    ...: }
    ...: result['a']('a')
    ...: 
Out[2]: 'A'

In [3]: result = {
    ...:   'a': lambda : 'A',
    ...:   'b': lambda : 'B',
    ...:   'c': lambda : 'C',
    ...:   None: lambda : 'Nothing else matters'

    ...: }
    ...: result['a']()
    ...: 
Out[3]: 'A'

编辑:我注意到我可以将None类型与词典一起使用。所以这会模仿switch ; case else

答案 21 :(得分:7)

运行功能的解决方案:

1[MyProperty]'
cannot be used for parameter of type 'Microsoft.EntityFrameworkCore.DbSet

其中foo1(),foo2(),foo3()和default()是函数

答案 22 :(得分:6)

def f(x):
     return 1 if x == 'a' else\
            2 if x in 'bcd' else\
            0 #default

简短易读,具有默认值,并支持条件和返回值中的表达式。

但是,它的效率低于带字典的解决方案。例如,Python必须在返回默认值之前扫描所有条件。

答案 23 :(得分:5)

您可以使用调度的字典:

with time zone

输出:

#!/usr/bin/env python


def case1():
    print("This is case 1")

def case2():
    print("This is case 2")

def case3():
    print("This is case 3")


token_dict = {
    "case1" : case1,
    "case2" : case2,
    "case3" : case3,
}


def main():
    cases = ("case1", "case3", "case2", "case1")
    for case in cases:
        token_dict[case]()


if __name__ == '__main__':
    main()

答案 24 :(得分:5)

我认为最好的方法是使用python语言习语来保持代码可测试。如前面的答案所示,我使用词典利用python结构和语言并保留" case"用不同方法隔离的代码。下面有一个类,但您可以直接使用模块,全局和函数。该类具有可以使用隔离进行测试的方法。 根据您的需要,您也可以使用静态方法和属性。

class ChoiceManager:

    def __init__(self):
        self.__choice_table = \
        {
            "CHOICE1" : self.my_func1,
            "CHOICE2" : self.my_func2,
        }

    def my_func1(self, data):
        pass

    def my_func2(self, data):
        pass

    def process(self, case, data):
        return self.__choice_table[case](data)

ChoiceManager().process("CHOICE1", my_data)

可以利用此方法同时使用类作为" __ choice_table"的键。通过这种方式,您可以避免 isinstance abuse 并保持一切清洁和可测试。

假设您必须处理来自网络或MQ的大量消息或数据包。每个数据包都有自己的结构和管理代码(以通用方式)。 使用上面的代码可以执行以下操作:

class PacketManager:

    def __init__(self):
        self.__choice_table = \
        {
            ControlMessage : self.my_func1,
            DiagnosticMessage : self.my_func2,
        }

    def my_func1(self, data):
        # process the control message here
        pass

    def my_func2(self, data):
        # process the diagnostic message here
        pass

    def process(self, pkt):
        return self.__choice_table[pkt.__class__](pkt)

pkt = GetMyPacketFromNet()
PacketManager().process(pkt)


# isolated test or isolated usage example
def test_control_packet():
    p = ControlMessage()
    PacketManager().my_func1(p)

所以复杂性不会在代码流中传播,而是以代码结构呈现

答案 25 :(得分:5)

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

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 - 装饰器

一起使用
@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

答案 26 :(得分:5)

我倾向于使用的解决方案也使用词典:

def decision_time( key, *args, **kwargs):
    def action1()
        """This function is a closure - and has access to all the arguments"""
        pass
    def action2()
        """This function is a closure - and has access to all the arguments"""
        pass
    def action3()
        """This function is a closure - and has access to all the arguments"""
        pass

   return {1:action1, 2:action2, 3:action3}.get(key,default)()

这样做的好处是它不会每次都尝试评估函数,你只需要确保外部函数获取内部函数所需的所有信息。

答案 27 :(得分:5)

简单,未经测试;每个条件都是独立评估的:没有直通,但所有情况都被评估(尽管要打开的表达式只评估一次),除非有一个break语句。例如,

for case in [expression]:
    if case == 1:
        print(end='Was 1. ')

    if case == 2:
        print(end='Was 2. ')
        break

    if case in (1, 2):
        print(end='Was 1 or 2. ')

    print(end='Was something. ')

打印Was 1. Was 1 or 2. Was something. (该死!为什么我不能在内联代码块中有尾随空格?)如果expression评估为1,{{1如果Was 2.评估为expression,则2 Was something.评估为其他内容。

答案 28 :(得分:4)

定义:

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

答案 29 :(得分:4)

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

device.Execute(new TurnOnCommand()) 

现在,您可以可以使用切换语句来完成此操作(如果Python提供了该语句),但是您会浪费时间,因为有些方法可以做到这一点。或者,也许您不那么明显:

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?”,不如问“为什么要切换Python”?因为这通常是更有趣的问题,并且经常会暴露出您要构建的产品的设计缺陷。

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

答案 30 :(得分:4)

阅读完答案后我感到非常困惑,但这一切都清除了:

def numbers_to_strings(argument):
    switcher = {
        0: "zero",
        1: "one",
        2: "two",
    }
    return switcher.get(argument, "nothing")

此代码类似于:

function(argument){
    switch(argument) {
        case 0:
            return "zero";
        case 1:
            return "one";
        case 2:
            return "two";
        default:
            return "nothing";
    }
}

检查Source以获取有关字典映射到函数的更多信息。

答案 31 :(得分:4)

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

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;
}

我们还可以创建一个辅助函数来执行此操作:

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

所以我们可以像这样使用它来做一个,两个和三个:

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

答案 32 :(得分:2)

只是将一些密钥映射到某些代码并不是真正的问题,因为大多数人都使用了dict。真正的诀窍是试图模仿整个下降和破坏事物。我不认为我曾经写过一个案例陈述,我用过那个“功能”。这是一个简单的过程。

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指示是否要破坏或通过。

答案 33 :(得分:2)

作为Mark Biek's answer的一个小变化,对于像this duplicate这样的不常见的情况,用户有一堆函数调用延迟参数打包(并且不值得构建一堆功能超出),而不是:

d = {
    "a1": lambda: a(1),
    "a2": lambda: a(2),
    "b": lambda: b("foo"),
    "c": lambda: c(),
    "z": lambda: z("bar", 25),
    }
return d[string]()

......你可以这样做:

d = {
    "a1": (a, 1),
    "a2": (a, 2),
    "b": (b, "foo"),
    "c": (c,)
    "z": (z, "bar", 25),
    }
func, *args = d[string]
return func(*args)

这当然更短,但它是否更具可读性是一个悬而未决的问题......

我认为,对于此特定用途,从lambda切换到partial可能更具可读性(尽管不是更简洁):

d = {
    "a1": partial(a, 1),
    "a2": partial(a, 2),
    "b": partial(b, "foo"),
    "c": c,
    "z": partial(z, "bar", 25),
    }
return d[string]()

...它的优点是可以很好地处理关键字参数:

d = {
    "a1": partial(a, 1),
    "a2": partial(a, 2),
    "b": partial(b, "foo"),
    "c": c,
    "k": partial(k, key=int),
    "z": partial(z, "bar", 25),
    }
return d[string]()

答案 34 :(得分:1)

虽然已经有足够的答案,但我想指出一个更简单,更强大的解决方案:

class Switch:
    def __init__(self, switches):
        self.switches = switches
        self.between = len(switches[0]) == 3

    def __call__(self, x):
        for line in self.switches:
            if self.between:
                if line[0] <= x < line[1]:
                    return line[2]
            else:
                if line[0] == x:
                    return line[1]
        return None


if __name__ == '__main__':
    between_table = [
        (1, 4, 'between 1 and 4'),
        (4, 8, 'between 4 and 8')
    ]

    switch_between = Switch(between_table)

    print('Switch Between:')
    for i in range(0, 10):
        if switch_between(i):
            print('{} is {}'.format(i, switch_between(i)))
        else:
            print('No match for {}'.format(i))


    equals_table = [
        (1, 'One'),
        (2, 'Two'),
        (4, 'Four'),
        (5, 'Five'),
        (7, 'Seven'),
        (8, 'Eight')
    ]
    print('Switch Equals:')
    switch_equals = Switch(equals_table)
    for i in range(0, 10):
        if switch_equals(i):
            print('{} is {}'.format(i, switch_equals(i)))
        else:
            print('No match for {}'.format(i))

输出:

Switch Between:
No match for 0
1 is between 1 and 4
2 is between 1 and 4
3 is between 1 and 4
4 is between 4 and 8
5 is between 4 and 8
6 is between 4 and 8
7 is between 4 and 8
No match for 8
No match for 9

Switch Equals:
No match for 0
1 is One
2 is Two
No match for 3
4 is Four
5 is Five
No match for 6
7 is Seven
8 is Eight
No match for 9

答案 35 :(得分:1)

我已经制作了一个Switch Case实现,并没有在外部使用ifs(它仍然在类中使用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]

答案 36 :(得分:1)

我从python docs找到了以下最有帮助的答案:

您可以使用if... elif... elif... else序列轻松完成此操作。已经有一些关于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_。如果没有这样的前缀,如果值来自不受信任的来源,攻击者就可以调用您对象上的任何方法。

答案 37 :(得分:1)

this answer by abarnert类似,这里有一个专门用于为每个案例调用单个函数的用例的解决方案。在交换机中,同时避免lambdapartial超简洁,同时仍然能够处理关键字参数:

class switch(object):
    NO_DEFAULT = object()

    def __init__(self, value, default=NO_DEFAULT):
        self._value = value
        self._result = default

    def __call__(self, option, func, *args, **kwargs):
        if self._value == option:
            self._result = func(*args, **kwargs)
        return self

    def pick(self):
        if self._result is switch.NO_DEFAULT:
            raise ValueError(self._value)

        return self._result

使用示例:

def add(a, b):
    return a + b

def double(x):
    return 2 * x

def foo(**kwargs):
    return kwargs

result = (
    switch(3)
    (1, add, 7, 9)
    (2, double, 5)
    (3, foo, bar=0, spam=8)
    (4, lambda: double(1 / 0))  # if evaluating arguments is not safe
).pick()

print(result)

请注意,这是链接呼叫,即switch(3)(...)(...)(...)。不要把逗号放在两者之间。将它全部放在一个表达式中也很重要,这就是为什么我在主调用周围使用额外的括号来隐式换行。

如果您打开未处理的值,例如上面的示例将引发错误,例如switch(5)(1, ...)(2, ...)(3, ...)。您可以改为提供默认值,例如switch(5, default=-1)...会返回-1

答案 38 :(得分:0)

以下适用于我的情况,当我需要一个简单的switch-case来调用一堆方法而不是只打印一些文本时。在使用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

答案 39 :(得分:0)

另一种选择:

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

答案 40 :(得分:0)

易于记忆:

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

答案 41 :(得分:0)

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

哦,如果你想做像开关一样的事情,请参阅here

答案 42 :(得分:-1)

也使用List存储案例,并通过select -

调用相应的函数
cases = ['zero()','one()','two()','three()']

def zero():
  print "method for 0 called..."
def one():
  print "method for 1 called..."
def two():
  print "method for 2 called..."
def three():
  print "method for 3 called..." 

i = int(raw_input("Enter choice between 0-3 "))

if(i<=len(cases)):
 exec(cases[i])
else:
 print "wrong choice"

也在screwdesk

解释

答案 43 :(得分:-2)

switch语句只是if / elif / else的语法糖。 任何控制语句正在做的是根据特定条件委派作业 - 决策路径。为了将其包装到模块中并且能够基于它的唯一id调用作业,可以利用继承和事实上,python中的任何方法都是虚拟的,以提供派生类特定的作业实现,具体为&#34; case&#34;处理

#!/usr/bin/python

import sys

class Case(object):
    """
        Base class wich specifies the interface for "case" handler.
        The all required arbitrary arguments inside "execute" method will be
        provided through the derived class
        specific constructor

        @note in python, all class methods are virtual
    """
    def __init__(self, id):
        self.id = id

    def pair(self):
        """
            Pairs the given id of the "case" with
            the instance on which "execute" will be called
        """
        return (self.id, self)

    def execute(self):#base class virtual method that needs to be overrided
        pass

class Case1(Case):
    def __init__(self, id, msg):
        self.id = id
        self.msg = msg
    def execute(self):#override the base class method
        print("<Case1> id={}, message: \"{}\"".format(str(self.id), self.msg))

class Case2(Case):
    def __init__(self, id, n):
        self.id = id
        self.n = n
    def execute(self):#override the base class method
        print("<Case2> id={}, n={}.".format(str(self.id), str(self.n)))
        print("\n".join(map(str, range(self.n))))



class Switch(object):
    """
        The class wich delegates the jobs
        based on the given job id
    """
    def __init__(self, cases):
        self.cases = cases#dictionary: time complexitiy for access operation is 1
    def resolve(self, id):

        try:
            cases[id].execute()
        except KeyError as e:
            print("Given id: {} is wrong!".format(str(id)))



if __name__ == '__main__':

    # Cases
    cases=dict([Case1(0, "switch").pair(), Case2(1, 5).pair()])

    switch = Switch(cases)

    # id will be dynamically specified
    switch.resolve(0)
    switch.resolve(1)
    switch.resolve(2)