在Python中替换switch语句?

时间:2020-03-05 18:52:37  来源:igfitidea点击:

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

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

解决方案

回答

我们可以使用字典:

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)

从这里

回答

如果我们实际上只是返回一个预定的固定值,则可以创建一个字典,将所有可能的输入索引作为键及其对应的值。另外,除非我们正以某种方式计算返回值,否则我们可能并不真的希望函数执行此操作。

哦,如果我们想做类似开关的操作,请参见此处。

回答

除了字典方法(我非常喜欢BTW)之外,我们还可以使用if-elif-else获取switch / case / default功能:

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更好,即使从功能上来说,它也更接近。

回答

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

回答

switch语句只是语法糖,这可能就是为什么Python没有它的原因。我们可以使用if else语句轻松实现此功能。

就像Matthew Schinckel所说的那样,可以使用if和elif等。

具有像大多数switch语句一样的"穿透"功能也是一件简单的事情。我们所要做的就是不使用elif。

if x == 1:
    # 1
if x == 2:
    # fall-through
elif x == 3:
    # not fall-through

回答

我只会使用if / elif / else语句。我认为替换掉switch语句就足够了。

回答

扩展" dict as switch"的想法。如果要为开关使用默认值:

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

回答

如果我们想使用默认值,则可以使用字典get(key [,default])方法:

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

回答

def f(x):    
  return {'a': 1,'b': 2,}.get(x) or "Default"

回答

我为此做了(相对)灵活和可重复使用的解决方案。可以在GitHub上找到该要点。如果switch函数的结果是可调用的,则会自动调用它。

回答

我使用的解决方案:

此处发布的两种解决方案的组合,相对易于阅读并支持默认设置。

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)

在字典中查找" lambda x:x 2"并将其与x = 23一起使用

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

不会在字典中找到它,而是使用默认的" lambda x:x 22"和x = 44.

回答

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

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

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

解决方案:

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

result = func(*args)

因此,我们将获得一个包含函数及其参数的列表。这样,仅返回函数指针和参数列表,而不对其求值。然后,"结果"将评估返回的函数调用。

回答

如果我们要搜索额外的语句,例如" switch",那么我将构建一个扩展Python的python模块。它被称为ESPY,称为" Python增强结构",并且可用于Python 2.x和Python3.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