我想用Python编写一个函数,根据输入索引的值返回不同的固定值。
在其他语言中,我会使用switch或case语句,但Python似乎没有switch语句。在此场景中,推荐的Python解决方案是什么?
我想用Python编写一个函数,根据输入索引的值返回不同的固定值。
在其他语言中,我会使用switch或case语句,但Python似乎没有switch语句。在此场景中,推荐的Python解决方案是什么?
当前回答
假设您不希望只返回一个值,而是希望使用更改对象上某些内容的方法。使用此处所述的方法将是:
result = {
'a': obj.increment(x),
'b': obj.decrement(x)
}.get(value, obj.default(x))
这里Python计算字典中的所有方法。
因此,即使您的值为“a”,对象也会递增和递减x。
解决方案:
func, args = {
'a' : (obj.increment, (x,)),
'b' : (obj.decrement, (x,)),
}.get(value, (obj.default, (x,)))
result = func(*args)
因此,您将得到一个包含函数及其参数的列表。这样,只返回函数指针和参数列表,而不计算result”然后计算返回的函数调用。
其他回答
如果您想要默认值,可以使用dictionary get(key[,default])函数:
def f(x):
return {
'a': 1,
'b': 2
}.get(x, 9) # 9 will be returned default if x is not found
如果您不担心丢失案例套件中的语法高亮显示,可以执行以下操作:
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')
""")
我从Twisted Python代码中学到了一种模式。
class SMTP:
def lookupMethod(self, command):
return getattr(self, 'do_' + command.upper(), None)
def do_HELO(self, rest):
return 'Howdy ' + rest
def do_QUIT(self, rest):
return 'Bye'
SMTP().lookupMethod('HELO')('foo.bar.com') # => 'Howdy foo.bar.com'
SMTP().lookupMethod('QUIT')('') # => 'Bye'
您可以在需要调度令牌和执行扩展代码段的任何时候使用它。在状态机中,您将有state_方法,并在self.state上分派。通过从基类继承并定义自己的do_方法,可以清晰地扩展此开关。通常,基类中甚至没有do_方法。
编辑:具体是如何使用的
如果是SMTP,您将收到来自网络的HELO。相关代码(来自twisted/mail/smtp.py,根据我们的情况进行了修改)如下
class SMTP:
# ...
def do_UNKNOWN(self, rest):
raise NotImplementedError, 'received unknown command'
def state_COMMAND(self, line):
line = line.strip()
parts = line.split(None, 1)
if parts:
method = self.lookupMethod(parts[0]) or self.do_UNKNOWN
if len(parts) == 2:
return method(parts[1])
else:
return method('')
else:
raise SyntaxError, 'bad syntax'
SMTP().state_COMMAND(' HELO foo.bar.com ') # => Howdy foo.bar.com
您将收到“HELO foo.bar.com”(或者您可能会收到“QUIT”或“RCPT TO:foo”)。这被标记为['HELO','foo.bar.com']。实际的方法查找名称取自部件[0]。
(原始方法也称为state_COMMAND,因为它使用相同的模式来实现状态机,即getattr(self,'state_'+self.mode))
仅仅将一些键映射到一些代码并不是一个真正的问题,正如大多数人在使用字典时所展示的那样。真正的诀窍是尝试模仿整个直通和中断过程。我认为我从来没有写过一个案例陈述,其中我使用了“功能”。这里有一个直通车。
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指示是否突破或放弃。
作为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]()