我想用Python编写一个函数,根据输入索引的值返回不同的固定值。
在其他语言中,我会使用switch或case语句,但Python似乎没有switch语句。在此场景中,推荐的Python解决方案是什么?
我想用Python编写一个函数,根据输入索引的值返回不同的固定值。
在其他语言中,我会使用switch或case语句,但Python似乎没有switch语句。在此场景中,推荐的Python解决方案是什么?
当前回答
如果您想要默认值,可以使用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
其他回答
在阅读了公认的答案后,我感到非常困惑,但这一切都清楚了:
def numbers_to_strings(argument):
switcher = {
0: "zero",
1: "one",
2: "two",
}
return switcher.get(argument, "nothing")
该代码类似于:
function(argument){
switch(argument) {
case 0:
return "zero";
case 1:
return "one";
case 2:
return "two";
default:
return "nothing";
}
}
有关字典映射到函数的详细信息,请查看源代码。
简单,未经测试;每个条件都是独立计算的:没有贯穿,但所有情况都会计算(尽管要打开的表达式只计算一次),除非有break语句。例如
for case in [expression]:
if case == 1:
print(end='Was 1. ')
if case == 2:
print(end='Was 2. ')
break
if case in (1, 2):
print(end='Was 1 or 2. ')
print(end='Was something. ')
指纹是1。是1或2。是什么。(该死!为什么在内联代码块中不能有尾随空格?)若表达式的计算结果为1,则为2。如果表达式的计算结果为2或Was某物。if表达式的计算结果为其他值。
我最喜欢的是一个非常好的食谱。这是我见过的最接近实际switchcase语句的语句,尤其是在特性中。
class switch(object):
def __init__(self, value):
self.value = value
self.fall = False
def __iter__(self):
"""Return the match method once, then stop"""
yield self.match
raise StopIteration
def match(self, *args):
"""Indicate whether or not to enter a case suite"""
if self.fall or not args:
return True
elif self.value in args: # changed for v1.5, see below
self.fall = True
return True
else:
return False
下面是一个示例:
# The following example is pretty much the exact use-case of a dictionary,
# but is included for its simplicity. Note that you can include statements
# in each suite.
v = 'ten'
for case in switch(v):
if case('one'):
print 1
break
if case('two'):
print 2
break
if case('ten'):
print 10
break
if case('eleven'):
print 11
break
if case(): # default, could also just omit condition or 'if True'
print "something else!"
# No need to break here, it'll stop anyway
# break is used here to look as much like the real thing as possible, but
# elif is generally just as good and more concise.
# Empty suites are considered syntax errors, so intentional fall-throughs
# should contain 'pass'
c = 'z'
for case in switch(c):
if case('a'): pass # only necessary if the rest of the suite is empty
if case('b'): pass
# ...
if case('y'): pass
if case('z'):
print "c is lowercase!"
break
if case('A'): pass
# ...
if case('Z'):
print "c is uppercase!"
break
if case(): # default
print "I dunno what c was!"
# As suggested by Pierre Quentel, you can even expand upon the
# functionality of the classic 'case' statement by matching multiple
# cases in a single shot. This greatly benefits operations such as the
# uppercase/lowercase example above:
import string
c = 'A'
for case in switch(c):
if case(*string.lowercase): # note the * for unpacking as arguments
print "c is lowercase!"
break
if case(*string.uppercase):
print "c is uppercase!"
break
if case('!', '?', '.'): # normal argument passing style also applies
print "c is a sentence terminator!"
break
if case(): # default
print "I dunno what c was!"
一些评论指出,使用foo作为case而不是foo中的case的上下文管理器解决方案可能更干净,对于大型switch语句,线性而不是二次行为可能是一个不错的选择。使用for循环的答案的一部分价值是有中断和突破的能力,如果我们愿意稍微使用我们选择的关键字,我们也可以在上下文管理器中实现这一点:
class Switch:
def __init__(self, value):
self.value = value
self._entered = False
self._broken = False
self._prev = None
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
return False # Allows a traceback to occur
def __call__(self, *values):
if self._broken:
return False
if not self._entered:
if values and self.value not in values:
return False
self._entered, self._prev = True, values
return True
if self._prev is None:
self._prev = values
return True
if self._prev != values:
self._broken = True
return False
if self._prev == values:
self._prev = None
return False
@property
def default(self):
return self()
下面是一个示例:
# Prints 'bar' then 'baz'.
with Switch(2) as case:
while case(0):
print('foo')
while case(1, 2, 3):
print('bar')
while case(4, 5):
print('baz')
break
while case.default:
print('default')
break
我从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))
扩展“dict as switch”思想。如果要为交换机使用默认值:
def f(x):
try:
return {
'a': 1,
'b': 2,
}[x]
except KeyError:
return 'default'