Python中switch语句的替换?

Python中switch语句的替换?,python,switch-statement,Python,Switch Statement,我想用Python编写一个函数,根据输入索引的值返回不同的固定值 在其他语言中,我会使用switch或case语句,但Python似乎没有switch语句。在这种情况下,推荐的Python解决方案是什么?下面的原始答案是在2008年编写的。从那时起,Python3.10(2021)引入了一条语句,该语句为Python提供了“开关”的一流实现。例如: def f(x): match x: case 'a': return 1 case

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


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

下面的原始答案是在2008年编写的。从那时起,Python3.10(2021)引入了一条语句,该语句为Python提供了“开关”的一流实现。例如:

def f(x):
    match x:
        case 'a':
            return 1
        case 'b':
            return 2
match
-
case
语句比这个简单的示例强大得多


你可以使用字典:

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

下面的原始答案写于2008年。从那时起,Python3.10(2021)引入了一条语句,该语句为Python提供了“开关”的一流实现。例如:

def f(x):
    match x:
        case 'a':
            return 1
        case 'b':
            return 2
match
-
case
语句比这个简单的示例强大得多


你可以使用字典:

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

我一直喜欢这样做

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

我一直喜欢这样做

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

除了字典方法(顺便说一句,我非常喜欢),您还可以使用
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

当然,这与switch/case不同-您不可能像退出
break
语句那样容易失败,但您可以进行更复杂的测试。它的格式比一系列嵌套的
if
s更好,尽管功能上它更接近于此。

除了字典方法(顺便说一句,我非常喜欢)之外,您还可以使用
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

当然,这与switch/case不同-您不可能像退出
break
语句那样容易失败,但您可以进行更复杂的测试。它的格式比一系列嵌套的
if
s更好,尽管在功能上更接近于此。

我从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'
您可以在需要分派令牌并执行扩展代码段的任何时候使用它。在状态机中,您将拥有
状态
方法,并在
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\u COMMAND
,因为它使用相同的模式来实现状态机,即
getattr(self,'state\u'+self.mode)

我从TwistedPython代码中学到了一种模式

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'
您可以在需要分派令牌并执行扩展代码段的任何时候使用它。在状态机中,您将拥有
状态
方法,并在
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\u COMMAND
,因为它使用相同的模式来实现状态机,即
getattr(self,'state\u'+self.mode)

扩展了“dict as switch”的思想。如果要为交换机使用默认值:

def f(x):
    try:
        return {
            'a': 1,
            'b': 2,
        }[x]
    except KeyError:
        return 'default'
扩展“dict as switch”的概念。如果要为交换机使用默认值:

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

如果希望使用默认值,可以使用dictionary方法:


如果希望使用默认值,可以使用dictionary方法:

我使用的解决方案:

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

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

在dict中查找
“lambda x:x-2”
,并将其与
x=23一起使用

.get('xxx', lambda x: x - 22)(44)
在dict中找不到它,使用默认的
“lambda x:x-22”
x=44

我使用的解决方案:

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

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

在dict中查找
“lambda x:x-2”
,并将其与
x=23一起使用

.get('xxx', lambda x: x - 22)(44)

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

假设您不想只返回一个值,而是想使用更改对象上某些内容的方法。使用此处所述的方法将是:

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)
这样就得到了一个包含函数及其参数的列表。只有这边
# Prints 'bar' then 'baz'.
with Switch(2) as case:
    while case(0):
        print('foo')
    while case(1, 2, 3):
        print('bar')
    while case(4, 5):
        print('baz')
        break
    while case.default:
        print('default')
        break
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 f(x):
     return 1 if x == 'a' else\
            2 if x in 'bcd' else\
            0 #default
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("!")),
    })
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")
    })
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.
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'
switch ...parameter...
case p1: v1; break;
case p2: v2; break;
default: v3;
(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)
match something:
    case 0 | 1 | 2:
        # Matches 0, 1 or 2
        print("Small number")
    case [] | [_]:
        # Matches an empty or single value sequence
        # Matches lists and tuples but not sets
        print("A short sequence")
    case str() | bytes():
        # Something of `str` or `bytes` type
        print("Something string-like")
    case _:
        # Anything not matched by the above
        print("Something else")
choices = {'a': 1, 'b': 2}
result = choices.get(key, 'default')
// 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'))
# 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
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
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
pip install NeoPySwitch
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";
    }
}
if something:
    return "first thing"
elif somethingelse:
    return "second thing"
elif yetanotherthing:
    return "third thing"
else:
    return "default thing"
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. ')
result = {
    'case1':     foo1, 
    'case2':     foo2,
    'case3':     foo3,
}.get(option)(parameters_optional)
option = number['type']
result = {
    'number':     value_of_int,  # result = value_of_int(number['value'])
    'text':       value_of_text, # result = value_of_text(number['value'])
    'binary':     value_of_bin,  # result = value_of_bin(number['value'])
}.get(option)(value['value'])
option = number['type']
result = {
    'number':     func_for_number, # result = func_for_number()
    'text':       func_for_text,   # result = func_for_text()
    'binary':     func_for_bin,    # result = func_for_bin()
}.get(option)()
def dispatch(self, value):
    method_name = 'visit_' + str(value)
    method = getattr(self, method_name)
    method()
if x == 1: print('first')
elif x == 2: print('second')
elif x == 3: print('third')
else: print('did not place')
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)()
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
def ConvertToReason(code):
    if (code == 200):
        return 'Okay'
    elif (code == 400):
        return 'Bad Request'
    elif (code == 404):
        return 'Not Found'
    else:
        return None
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
#!/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()