在Python中替换switch语句?
我想用Python编写一个函数,该函数根据输入索引的值返回不同的固定值。
在其他语言中,我将使用switch
或者case
语句,但是Python似乎没有switch
语句。在这种情况下,推荐的Python解决方案是什么?
解决方案
回答
我们可以使用字典:
def f(x): return { 'a': 1, 'b': 2, }[x]
回答
我一直很喜欢这样
result = { 'a': lambda x: x * 5, 'b': lambda x: x + 7, 'c': lambda x: x - 2 }[value](x)
从这里
回答
如果我们实际上只是返回一个预定的固定值,则可以创建一个字典,将所有可能的输入索引作为键及其对应的值。另外,除非我们正以某种方式计算返回值,否则我们可能并不真的希望函数执行此操作。
哦,如果我们想做类似开关的操作,请参见此处。
回答
除了字典方法(我非常喜欢BTW)之外,我们还可以使用if-elif-else获取switch / case / default功能:
if x == 'a': # Do the thing elif x == 'b': # Do the other thing if x in 'bc': # Fall-through by not using elif, but now the default case includes case 'a'! elif x in 'xyz': # Do yet another thing else: # Do the default
当然,这与开关/保护套不一样,因为我们不能像中断那样容易地掉线。语句,但是我们可以进行更复杂的测试。它的格式比一系列嵌套的ifs更好,即使从功能上来说,它也更接近。
回答
我从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'
)。这被标记为parts
中的['HELO','foo.bar.com']
。实际的方法查找名称取自parts [0]
。
(原始方法也称为state_COMMAND
,因为它使用相同的模式来实现状态机,即getattr(self,'state_'+ self.mode)
)
回答
switch语句只是语法糖,这可能就是为什么Python没有它的原因。我们可以使用if else语句轻松实现此功能。
就像Matthew Schinckel所说的那样,可以使用if和elif等。
具有像大多数switch语句一样的"穿透"功能也是一件简单的事情。我们所要做的就是不使用elif。
if x == 1: # 1 if x == 2: # fall-through elif x == 3: # not fall-through
回答
我只会使用if / elif / else语句。我认为替换掉switch语句就足够了。
回答
扩展" dict as switch"的想法。如果要为开关使用默认值:
def f(x): try: return { 'a': 1, 'b': 2, }[x] except KeyError: return 'default'
回答
如果我们想使用默认值,则可以使用字典get(key [,default])
方法:
def f(x): return { 'a': 1, 'b': 2 }.get(x, 9) # 9 is default if x not found
回答
def f(x): return {'a': 1,'b': 2,}.get(x) or "Default"
回答
我为此做了(相对)灵活和可重复使用的解决方案。可以在GitHub上找到该要点。如果switch函数的结果是可调用的,则会自动调用它。
回答
我使用的解决方案:
此处发布的两种解决方案的组合,相对易于阅读并支持默认设置。
result = { 'a': lambda x: x * 5, 'b': lambda x: x + 7, 'c': lambda x: x - 2 }.get(whatToUse, lambda x: x - 22)(value)
在哪里
.get('c', lambda x: x - 22)(23)
在字典中查找" lambda x:x 2"
并将其与x = 23
一起使用
.get('xxx', lambda x: x - 22)(44)
不会在字典中找到它,而是使用默认的" lambda x:x 22"和x = 44.
回答
假设我们不想只返回一个值,而是想使用更改对象上某些内容的方法。使用此处说明的方法将是:
result = { 'a': obj.increment(x), 'b': obj.decrement(x) }.get(value, obj.default(x))
这里发生的是python评估字典中的所有方法。
因此,即使值为" a",对象也会增加x或者减少x。
解决方案:
func, args = { 'a' : (obj.increment, (x,)), 'b' : (obj.decrement, (x,)), }.get(value, (obj.default, (x,))) result = func(*args)
因此,我们将获得一个包含函数及其参数的列表。这样,仅返回函数指针和参数列表,而不对其求值。然后,"结果"将评估返回的函数调用。
回答
如果我们要搜索额外的语句,例如" switch",那么我将构建一个扩展Python的python模块。它被称为ESPY,称为" Python增强结构",并且可用于Python 2.x和Python3.x。
例如,在这种情况下,可以通过以下代码执行switch语句:
macro switch(arg1): while True: cont=False val=%arg1% socket case(arg2): if val==%arg2% or cont: cont=True socket socket else: socket break
可以这样使用:
a=3 switch(a): case(0): print("Zero") case(1): print("Smaller than 2"): break else: print ("greater than 1")
因此,espy在Python中将其翻译为:
a=3 while True: cont=False if a==0 or cont: cont=True print ("Zero") if a==1 or cont: cont=True print ("Smaller than 2") break print ("greater than 1") break