我想用Python编写一个函数,根据输入索引的值返回不同的固定值。
在其他语言中,我会使用switch或case语句,但Python似乎没有switch语句。在此场景中,推荐的Python解决方案是什么?
我想用Python编写一个函数,根据输入索引的值返回不同的固定值。
在其他语言中,我会使用switch或case语句,但Python似乎没有switch语句。在此场景中,推荐的Python解决方案是什么?
当前回答
我喜欢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类型。因此,这将模拟交换机;其他情况
其他回答
我认为最好的方法是使用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)
因此,复杂性不会在代码流中扩散,而是在代码结构中呈现。
我倾向于使用字典的解决方案是:
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)()
这样做的优点是它不需要每次都对函数求值,您只需确保外部函数获得内部函数所需的所有信息。
我在谷歌搜索上找不到简单的答案。但我还是想通了。这真的很简单。决定把它贴出来,也许可以防止别人的头上少刮几下。关键是简单的“in”和元组。下面是带有直通的switch语句行为,包括RANDOM直通。
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.
与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。
作为Mark Biek答案的一个小变化,对于像这样的不常见情况,用户有一堆函数调用要延迟,而参数要打包(而且不值得构建一堆不符合逻辑的函数),而不是这样:
d = {
"a1": lambda: a(1),
"a2": lambda: a(2),
"b": lambda: b("foo"),
"c": lambda: c(),
"z": lambda: z("bar", 25),
}
return d[string]()
…您可以这样做:
d = {
"a1": (a, 1),
"a2": (a, 2),
"b": (b, "foo"),
"c": (c,)
"z": (z, "bar", 25),
}
func, *args = d[string]
return func(*args)
这当然更短,但它是否更可读是一个悬而未决的问题…
我认为从lambda转换为partial可能更容易理解(虽然不是更简单):
d = {
"a1": partial(a, 1),
"a2": partial(a, 2),
"b": partial(b, "foo"),
"c": c,
"z": partial(z, "bar", 25),
}
return d[string]()
…它的优点是可以很好地处理关键字参数:
d = {
"a1": partial(a, 1),
"a2": partial(a, 2),
"b": partial(b, "foo"),
"c": c,
"k": partial(k, key=int),
"z": partial(z, "bar", 25),
}
return d[string]()