我想用Python编写一个函数,根据输入索引的值返回不同的固定值。
在其他语言中,我会使用switch或case语句,但Python似乎没有switch语句。在此场景中,推荐的Python解决方案是什么?
我想用Python编写一个函数,根据输入索引的值返回不同的固定值。
在其他语言中,我会使用switch或case语句,但Python似乎没有switch语句。在此场景中,推荐的Python解决方案是什么?
当前回答
我最喜欢的是一个非常好的食谱。这是我见过的最接近实际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
其他回答
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.
作为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]()
我最喜欢的是一个非常好的食谱。这是我见过的最接近实际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
虽然已经有了足够的答案,但我想指出一个更简单、更强大的解决方案:
class Switch:
def __init__(self, switches):
self.switches = switches
self.between = len(switches[0]) == 3
def __call__(self, x):
for line in self.switches:
if self.between:
if line[0] <= x < line[1]:
return line[2]
else:
if line[0] == x:
return line[1]
return None
if __name__ == '__main__':
between_table = [
(1, 4, 'between 1 and 4'),
(4, 8, 'between 4 and 8')
]
switch_between = Switch(between_table)
print('Switch Between:')
for i in range(0, 10):
if switch_between(i):
print('{} is {}'.format(i, switch_between(i)))
else:
print('No match for {}'.format(i))
equals_table = [
(1, 'One'),
(2, 'Two'),
(4, 'Four'),
(5, 'Five'),
(7, 'Seven'),
(8, 'Eight')
]
print('Switch Equals:')
switch_equals = Switch(equals_table)
for i in range(0, 10):
if switch_equals(i):
print('{} is {}'.format(i, switch_equals(i)))
else:
print('No match for {}'.format(i))
输出:
Switch Between:
No match for 0
1 is between 1 and 4
2 is between 1 and 4
3 is between 1 and 4
4 is between 4 and 8
5 is between 4 and 8
6 is between 4 and 8
7 is between 4 and 8
No match for 8
No match for 9
Switch Equals:
No match for 0
1 is One
2 is Two
No match for 3
4 is Four
5 is Five
No match for 6
7 is Seven
8 is Eight
No match for 9
我要把我的两分钱放在这里。Python中没有case/switch语句的原因是因为Python遵循“只有一种正确的方法”的原则。很明显,您可以想出各种方法来重新创建switch/case功能,但实现这一点的Python方法是if/elf构造。即。,
if something:
return "first thing"
elif somethingelse:
return "second thing"
elif yetanotherthing:
return "third thing"
else:
return "default thing"
我只是觉得PEP 8应该在这里获得认可。Python的一个优点是它的简单和优雅。这在很大程度上源于PEP8中提出的原则,包括“只有一种正确的方法可以做某事。”