我想用Python编写一个函数,根据输入索引的值返回不同的固定值。
在其他语言中,我会使用switch或case语句,但Python似乎没有switch语句。在此场景中,推荐的Python解决方案是什么?
我想用Python编写一个函数,根据输入索引的值返回不同的固定值。
在其他语言中,我会使用switch或case语句,但Python似乎没有switch语句。在此场景中,推荐的Python解决方案是什么?
当前回答
仅仅将一些键映射到一些代码并不是一个真正的问题,正如大多数人在使用字典时所展示的那样。真正的诀窍是尝试模仿整个直通和中断过程。我认为我从来没有写过一个案例陈述,其中我使用了“功能”。这里有一个直通车。
def case(list): reduce(lambda b, f: (b | f[0], {False:(lambda:None),True:f[1]}[b | f[0]]())[0], list, False)
case([
(False, lambda:print(5)),
(True, lambda:print(4))
])
我真的把它想象成一个单独的陈述。我希望你能原谅这种愚蠢的格式。
reduce(
initializer=False,
function=(lambda b, f:
( b | f[0]
, { False: (lambda:None)
, True : f[1]
}[b | f[0]]()
)[0]
),
iterable=[
(False, lambda:print(5)),
(True, lambda:print(4))
]
)
我希望这是有效的Python代码。它应该能让你通过。当然,布尔检查可以是表达式,如果您希望它们被延迟求值,那么可以将它们全部封装在lambda中。在执行了列表中的一些项目之后,也不难让它被接受。只需创建元组(bool,bool,function),其中第二个bool指示是否突破或放弃。
其他回答
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)
def f(x):
return 1 if x == 'a' else\
2 if x in 'bcd' else\
0 #default
简短易读,具有默认值,支持条件和返回值中的表达式。
然而,它的效率不如字典解决方案。例如,Python必须在返回默认值之前扫描所有条件。
仅仅将一些键映射到一些代码并不是一个真正的问题,正如大多数人在使用字典时所展示的那样。真正的诀窍是尝试模仿整个直通和中断过程。我认为我从来没有写过一个案例陈述,其中我使用了“功能”。这里有一个直通车。
def case(list): reduce(lambda b, f: (b | f[0], {False:(lambda:None),True:f[1]}[b | f[0]]())[0], list, False)
case([
(False, lambda:print(5)),
(True, lambda:print(4))
])
我真的把它想象成一个单独的陈述。我希望你能原谅这种愚蠢的格式。
reduce(
initializer=False,
function=(lambda b, f:
( b | f[0]
, { False: (lambda:None)
, True : f[1]
}[b | f[0]]()
)[0]
),
iterable=[
(False, lambda:print(5)),
(True, lambda:print(4))
]
)
我希望这是有效的Python代码。它应该能让你通过。当然,布尔检查可以是表达式,如果您希望它们被延迟求值,那么可以将它们全部封装在lambda中。在执行了列表中的一些项目之后,也不难让它被接受。只需创建元组(bool,bool,function),其中第二个bool指示是否突破或放弃。
我认为最好的方法是使用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)
因此,复杂性不会在代码流中扩散,而是在代码结构中呈现。
我发现Python文档中的以下答案非常有用:
你可以通过一系列if…elif。。。埃利夫。。。其他的关于switch语句语法已经有了一些建议,但对于是否以及如何进行范围测试还没有达成共识。有关完整详细信息和当前状态,请参见PEP 275。
对于需要从大量可能性中进行选择的情况,可以创建一个字典,将大小写值映射到要调用的函数。例如:
def function_1(...):
...
functions = {'a': function_1,
'b': function_2,
'c': self.method_1, ...}
func = functions[value]
func()
对于在对象上调用方法,可以通过使用内置的getattr()来检索具有特定名称的方法来进一步简化:
def visit_a(self, ...):
...
...
def dispatch(self, value):
method_name = 'visit_' + str(value)
method = getattr(self, method_name)
method()
建议为方法名称使用前缀,例如本例中的visit_。如果没有这样的前缀,如果值来自不受信任的源,攻击者将能够调用对象上的任何方法。