我想用Python编写一个函数,根据输入索引的值返回不同的固定值。
在其他语言中,我会使用switch或case语句,但Python似乎没有switch语句。在此场景中,推荐的Python解决方案是什么?
我想用Python编写一个函数,根据输入索引的值返回不同的固定值。
在其他语言中,我会使用switch或case语句,但Python似乎没有switch语句。在此场景中,推荐的Python解决方案是什么?
当前回答
def f(x):
return 1 if x == 'a' else\
2 if x in 'bcd' else\
0 #default
简短易读,具有默认值,支持条件和返回值中的表达式。
然而,它的效率不如字典解决方案。例如,Python必须在返回默认值之前扫描所有条件。
其他回答
我一直喜欢这样做
result = {
'a': lambda x: x * 5,
'b': lambda x: x + 7,
'c': lambda x: x - 2
}[value](x)
从这里开始
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.
如果您不担心丢失案例套件中的语法高亮显示,可以执行以下操作:
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;
}
我们还可以创建一个helper函数来实现这一点:
def switch(value, cases, default):
exec cases.get(value, default)
因此,我们可以将其用于一、二和三的示例:
switch(value, {
1: """
print ('one')
""",
2: """
print ('two')
""",
3: """
print ('three')
""",
}, """
print ('None')
""")
我认为最好的方法是使用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)
因此,复杂性不会在代码流中扩散,而是在代码结构中呈现。
与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。