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

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


当前回答

与abarnert的回答类似,这里有一个专门针对以下用例的解决方案:为开关中的每个“case”调用单个函数,同时避免lambda或partial,以实现超简洁,同时仍然能够处理关键字参数:

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)(…)(。将所有内容放在一个表达式中也很重要,这就是为什么我在隐式行延续的主调用周围使用了额外的括号。

如果您打开未处理的值,例如开关(5)(1,…)(2,…)。。。返回-1。

其他回答

如果要搜索额外的语句,如“switch”,我构建了一个扩展Python的Python模块。它被称为ESPY“增强的Python结构”,可用于Python2.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

还可以使用列表存储案例,并通过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"

也在螺丝台上进行了解释。

switch语句只是if/elif/else的语法糖。任何控制语句所做的都是基于某个条件(即决策路径)来授权作业。为了将其包装到模块中并能够基于其唯一id调用作业,可以使用继承和Python中的任何方法都是虚拟的这一事实来提供派生类特定的作业实现,作为特定的“case”处理程序:

#!/usr/bin/python

import sys

class Case(object):
    """
        Base class which specifies the interface for the "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 overridden
        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 which delegates the jobs
        based on the given job id
    """
    def __init__(self, cases):
        self.cases = cases # dictionary: time complexity for the 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)

我喜欢Mark Bies的回答

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

我必须运行结果[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类型。因此,这将模拟交换机;其他情况

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

哦,如果你想做一些类似开关的事情,请看这里。