我需要一个代码帮助,我想在python中实现switch case模式,所以就像一些教程说的那样,我可以使用字典,但这是我的问题:
# type can be either create or update or ..
message = { 'create':msg(some_data),
'update':msg(other_data)
# can have more
}
return message(type)
但是它对我不起作用,因为some_data或other_data可以是None(如果没有则会引发错误)并且msg函数需要很简单(我不想在其中加入一些条件)。
这里的问题是每次执行函数msg()以填充dict
与切换案例模式不同,通常使用其他编程语言的人不会执行case
中的代码,除非它是匹配的。
还有其他方法可以做到这一点,或者我只需要做,如果elif ......
更新 谢谢你所有的回复,但实际上它更像是这个
message = { 'create': "blabla %s" % msg(some_data),
'update': "blabla %s" % msg(other_data)
'delete': "blabla %s" % diff(other_data, some_data)
}
所以lambda在这里不起作用而且没有调用相同的函数,所以它更像是我需要的真实开关案例,也许我必须考虑其他模式。
答案 0 :(得分:9)
message = { 'create':msg(some_data or ''),
'update':msg(other_data or '')
# can have more
}
更好的是,为了防止msg
被执行只是为了填补字典:
message = { 'create':(msg,some_data),
'update':(msg,other_data),
# can have more
}
func,data=message[msg_type]
func(data)
现在您可以自由定义一个更合理的msg
函数,该函数可以处理等于None
的参数:
def msg(data):
if data is None: data=''
...
答案 1 :(得分:9)
这听起来比你需要的更复杂。你想要简单吗?
if mytype == 'create':
return msg(some_data)
elif mytype == 'update':
return msg(other_data)
else:
return msg(default_data)
有时,一个无聊,明确的if/else
块正是您所需要的。即使是团队中最新的程序员也很清楚,并且不会不必要地调用msg()。我也愿意打赌,这将比你正在处理的其他解决方案更快,除非案例数量增长并且msg()闪电般快。
答案 2 :(得分:3)
在我学习python之前5年,我在开关发明游戏中突然出现了笑话:Readable switch construction without lambdas or dictionaries。那好吧。请阅读下面的另一种方法。
下面。有一个switch语句。 (@martineau的一些很好的清理工作)
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'
我将免费投入(适度)黑客堆栈,滥用装饰器和可疑的上下文管理器。它很丑陋但功能强大(并没有很好的方式)。从本质上讲,它所做的只是将字典逻辑包装在一个丑陋的包装器中。
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语句中出现的定义不会泄漏到封闭范围内并将case
放入命名空间。如果你不介意泄漏,(例如循环泄漏),那么你可以使用with语句中的case
子句删除堆栈hack并从__enter__
返回as
装饰器在封闭范围内接收它。
答案 3 :(得分:2)
您可以在lambda中隐藏评估:
message = { 'create': lambda: msg(some_data),
'update': lambda: msg(other_data),
}
return message[type]()
只要名称全部被定义(所以你没有得到NameError
),你也可以这样构造它:
message = { 'create': (msg, some_data),
'update': (other_func, other_data),
}
func, arg = message[type]
return func(arg)
答案 4 :(得分:2)
这里有点不同(虽然有点类似于@ Tumbleweed),可以说更像是“面向对象”。您可以使用Python类(包含字典),而不是显式使用字典来处理各种情况。
这种方法为Python代码提供了一个相当自然的C / C ++ switch
语句转换。与后者一样,它推迟处理每个案例的代码的执行,并允许提供默认的代码。
与案例对应的每个switch
类方法的代码可以包含多行代码,而不是此处显示的单个return <expression>
代码,并且只编译一次。但是,一个区别或限制是,一种方法中的处理将不会也不能自动“落入”下一代码的代码中(这不是示例中的问题,而是好的)。
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_)
答案 5 :(得分:1)
您可以使用lambda
延迟执行匹配:
return {
'create': lambda: msg(some_data),
'update': lambda: msg(other_data),
# ...
}[type]()
如果所有案例都只是使用不同的参数调用msg
,您可以将其简化为:
return msg({
'create': some_data,
'update': other_data,
# ...
}[type])
答案 6 :(得分:1)
如何创建新类并将数据/参数包装在对象中 - 所以不要通过传递参数来绑定数据 - 你可以让函数决定它需要哪些参数......
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')
答案 7 :(得分:0)
啊没关系,这解释了。我在想elif http://bytebaker.com/2008/11/03/switch-case-statement-in-python/
答案 8 :(得分:0)
由于您希望在每种情况下执行的代码来自安全源,您可以将每个代码段存储在字典中的单独字符串表达式中,并按以下方式执行操作:
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_])
最后一行的表达式也可以是eval(message.get(type_, '"unknown type_"'))
以提供默认值。无论哪种方式,为了保持可读性,可以隐藏丑陋的细节:
switch = lambda type_: eval(message.get(type_, '"unknown type_"'))
return switch(type_)
代码片段甚至可以以更快的速度进行预编译:
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')