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

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


当前回答

运行函数的解决方案:

result = {
    'case1':     foo1, 
    'case2':     foo2,
    'case3':     foo3,
}.get(option)(parameters_optional)

其中foo1()、foo2()和foo3()是函数

示例1(带参数):

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

示例2(无参数):

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

示例4(仅限值):

option = number['type']
result = {
    'number':    lambda: 10,       # result = 10
    'text':      lambda: 'ten',    # result = 'ten'
    'binary':    lambda: 0b101111, # result = 47
}.get(option)()

其他回答

我认为最好的方法是使用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”的键来利用此方法。通过这种方式,您可以避免信息滥用,并保持所有信息的清洁和可测试性。

假设您必须处理来自网络或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)

因此,复杂性不会在代码流中扩散,而是在代码结构中呈现。

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

Python 3.10(2021)引入了match-case语句,该语句提供了Pythons“switch”的一流实现。例如:

def f(x):
    match x:
        case 'a':
            return 1
        case 'b':
            return 2
        case _:
            return 0   # 0 is the default case if x is not found

match-case语句比这个简单的示例强大得多。


以下原始答案写于2008年,当时还未提供匹配案例:

你可以用字典:

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
}.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。