switch case in python doesn't work; need another pattern
我需要一个关于代码的帮助,我想在python中实现switch case模式,就像一些教程所说的那样,我可以使用字典来实现这个功能,但我的问题是:
1 2 3 4 5 6 7 | # type can be either create or update or .. message = { 'create':msg(some_data), 'update':msg(other_data) # can have more } return message(type) |
但是它对我不起作用,因为有些数据或其他数据可能是无的(如果不是,它会引发错误),并且msg函数需要简单(我不想在其中加入某些条件)。
这里的问题是每次执行函数msg()来填充dict与通常使用其他编程语言的switch case模式不同的是,除非匹配,否则switch case模式不会执行
有没有其他方法可以这样做,或者我只需要这样做,如果伊利夫…
更新:谢谢你所有的回复,但实际上更像这样
1 2 3 4 | message = { 'create':"blabla %s" % msg(some_data), 'update':"blabla %s" % msg(other_data) 'delete':"blabla %s" % diff(other_data, some_data) } |
所以lambda在这里不起作用,也不调用相同的函数,所以它更像是我需要的一个真正的开关案例,也许我需要考虑其他模式。
听起来你把这件事复杂化了。你想要简单点?
1 2 3 4 5 6 | if mytype == 'create': return msg(some_data) elif mytype == 'update': return msg(other_data) else: return msg(default_data) |
您不必仅仅因为可以使用dict和函数引用。有时,一个无聊的、明确的
1 2 3 4 | message = { 'create':msg(some_data or ''), 'update':msg(other_data or '') # can have more } |
更妙的是,为了防止执行
1 2 3 4 5 6 | message = { 'create':(msg,some_data), 'update':(msg,other_data), # can have more } func,data=message[msg_type] func(data) |
现在您可以自由定义一个更合理的
1 2 3 | def msg(data): if data is None: data='' ... |
在我学习python之前的5年里,我被灌输了开关发明游戏:没有lambda或字典的可读开关结构。哦,好吧。阅读下面的另一种方法。
在这里。有一个switch语句。(有@martineau的一些不错的清洁服务)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | with switch(foo): @case(1) def _(): print"1" @case(2) def _(): print"2" @case(3) def _(): print"3" @case(5) @case(6) def _(): print '5 and 6' @case.default def _(): print 'default' |
我将免费加入(适度的)黑客堆栈、滥用的装饰器和可疑的上下文管理器。它很难看,但功能正常(而且不是很好)。基本上,它所做的就是用一个丑陋的包装器包装字典逻辑。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | import inspect class switch(object): def __init__(self, var): self.cases = {} self.var = var def __enter__(self): def case(value): def decorator(f): if value not in self.cases: self.cases[value] = f return f return decorator def default(f): self.default = f return f case.default = default f_locals = inspect.currentframe().f_back.f_locals self.f_locals = f_locals.copy() f_locals['case'] = case def __exit__(self, *args, **kwargs): new_locals = inspect.currentframe().f_back.f_locals new_items = [key for key in new_locals if key not in self.f_locals] for key in new_items: del new_locals[key] # clean up new_locals.update(self.f_locals) # this reverts all variables to their try: # previous values self.cases[self.var]() except KeyError: try: getattr(self, 'default')() except AttributeError: pass |
注意,黑客堆栈实际上并不必要。我们只是使用它来创建一个作用域,这样switch语句中出现的定义就不会泄漏到封闭作用域中,也不会将
这里有一点不同(虽然有点类似于@torbeweed),而且可以说更"面向对象"。您可以使用Python类(包含字典)来代替显式使用字典来处理各种情况。
这种方法提供了一个看似自然的C/C++ EDCOX1,12个语句到Python代码的翻译。与后者一样,它推迟了处理每种情况的代码的执行,并允许提供默认的代码。
与案例对应的每个
1 2 3 4 5 6 7 8 9 10 | class switch: def create(self): return"blabla %s" % msg(some_data) def update(self): return"blabla %s" % msg(other_data) def delete(self): return"blabla %s" % diff(other_data, some_data) def _default(self): return"unknown type_" def __call__(self, type_): return getattr(self, type_, self._default)() switch = switch() # only needed once return switch(type_) |
可以将计算隐藏在lambda中:
1 2 3 4 | message = { 'create': lambda: msg(some_data), 'update': lambda: msg(other_data), } return message[type]() |
只要所有的名称都定义好了(这样你就不会得到一个
1 2 3 4 5 | message = { 'create': (msg, some_data), 'update': (other_func, other_data), } func, arg = message[type] return func(arg) |
创建新的类并将数据/参数包装在对象中,这样就可以让函数决定它需要哪些参数,而不是通过传递参数来绑定数据…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | class MyObj(object): def __init__(self, data, other_data): self.data = data self.other_data = other_data def switch(self, method_type): return { "create": self.msg, "update": self.msg, "delete": self.delete_func, }[method_type]() def msg(self): #process self.data return"Hello, World !!" def delete_func(self): #process other data self.other_data or anything else.... return True if"__main__" == __name__: m1 = MyObj(1,2) print m1.switch('create') print m1.switch('delete') |
您可以使用
1 2 3 4 5 | return { 'create': lambda: msg(some_data), 'update': lambda: msg(other_data), # ... }[type]() |
如果所有的情况都只是用不同的参数调用
1 2 3 4 5 | return msg({ 'create': some_data, 'update': other_data, # ... }[type]) |
由于在每种情况下要执行的代码都来自安全的源代码,因此可以将每个代码段存储在字典中的单独字符串表达式中,并沿着这些行执行一些操作:
1 2 3 4 5 6 | message = { 'create': '"blabla %s" % msg(some_data)', 'update': '"blabla %s" % msg(other_data)', 'delete': '"blabla %s" % diff(other_data, some_data)' } return eval(message[type_]) |
最后一行的表达式也可以是
1 2 3 | switch = lambda type_: eval(message.get(type_, '"unknown type_"')) return switch(type_) |
甚至可以更快地预编译代码片段:
1 2 3 4 | from compiler import compile # deprecated since version 2.6: Removed in Python 3 for k in message: message[k] = compile(message[k], 'message case', 'eval') |
啊,没关系,这就解释了。我在想伊利夫http://bytebaker.com/2008/11/03/switch-case-statement-in-python/