python中的开关大小写不';不工作;需要另一种模式吗

python中的开关大小写不';不工作;需要另一种模式吗,python,design-patterns,Python,Design Patterns,我需要一个代码方面的帮助,我想用python实现switch case模式,所以就像一些教程所说的,我可以使用字典来实现,但我的问题是: # type can be either create or update or .. message = { 'create':msg(some_data), 'update':msg(other_data) # can have more } return me

我需要一个代码方面的帮助,我想用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)
但它对我不起作用,因为某些_数据或其他_数据可以是None(如果它是None,则会引发错误),并且msg函数需要简单(我不想在其中设置一些条件)

这里的问题是每次填充dict时都会执行函数msg() 与switch case模式不同,switch case模式通常在其他编程语言中不执行
case
中的代码,除非它是匹配的

有没有其他方法可以做到这一点,或者我只需要做,如果埃利夫

更新: 谢谢你的回复,但实际上是这样的

message = { 'create': "blabla %s" % msg(some_data),
            'update': "blabla %s" % msg(other_data)
            'delete': "blabla %s" % diff(other_data, some_data)
           }
所以lambda在这里不起作用,也没有调用相同的函数,所以它更像是我需要的一个真正的开关案例,也许我必须考虑另一种模式

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=''
    ...

啊,没关系,这就解释了。我在想艾利夫

您可以使用
lambda
延迟匹配的执行:

return {
    'create': lambda: msg(some_data),
    'update': lambda: msg(other_data),
    # ...
}[type]()
如果所有案例都只是使用不同的参数调用
msg
,您可以将其简化为:

return msg({
    'create': some_data,
    'update': other_data,
    # ...
}[type])

您可以将评估隐藏在lambda中:

message = { 'create': lambda: msg(some_data),
            'update': lambda: msg(other_data),
          }
return message[type]()
只要所有名称都已定义(因此不会出现
namererror
),您也可以这样构造它:

message = { 'create': (msg, some_data),
            'update': (other_func, other_data),
          }
func, arg = message[type]
return func(arg)

创建新类并将数据/参数包装到对象中怎么样?这样,您就可以让函数决定它需要哪些参数,而不是通过传递参数来绑定数据

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')

听起来你把这件事复杂化了。你想要简单的

if mytype == 'create':
    return msg(some_data)
elif mytype == 'update':
    return msg(other_data)
else:
    return msg(default_data)

您不必仅仅因为可以就使用dict和函数引用。有时,一个无聊的、明确的
if/else
块正是您所需要的。即使是团队中最新的程序员也很清楚,永远不会不必要地调用msg()。我还愿意打赌,这将比您正在使用的其他解决方案更快,除非案例数量越来越大,msg()的速度非常快。

因为您希望在每个案例中执行的代码都来自安全的源代码,您可以将每个代码段存储在字典中单独的字符串表达式中,并按照以下方式执行操作:

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')

在我学习python之前的5年里,我就已经在发明交换机的游戏中失败了。哦,好吧。阅读下面的另一种方法


在这里。有一个switch语句。(由@martineau进行了一些漂亮的清理)

我将免费扔掉(适度)被黑客攻击的堆栈、被滥用的装饰程序和有问题的上下文管理器。它很难看,但很实用(而且不是很好)。本质上,它所做的只是将字典逻辑包装在一个丑陋的包装器中

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
放入命名空间中。如果您不介意泄漏(例如循环泄漏),那么您可以删除堆栈hack并从
\uuuuuu enter\uuuuuu
返回
案例
装饰器,使用with语句上的
as
子句在封闭范围内接收它。

这里有一些不同之处(尽管有点类似于@rumbweed)而且可以说更“面向对象”。您可以使用Python类(包含字典),而不是显式地使用字典来处理各种情况

这种方法将C/C++
switch
语句转换为Python代码,看起来相当自然。与后者一样,它推迟了处理每种情况的代码的执行,并允许提供默认情况

与一个case对应的每个
开关
类方法的代码可以由多行代码组成,而不是此处显示的单个
返回
代码,并且只编译一次。不过,一个区别或限制是,一个方法中的处理不会也不能自动“落入”下一个方法的代码中(这在示例中不是问题,但会很好)


很抱歉,如果我没有提到这一点,但它是python,python没有。是的,在我点击submit并查看我的旧代码后,我记得。我已经有一段时间没有使用python了,我只是非常抱歉,但并不是所有的情况都使用msg()@Unknown,如果代码看起来不可读,你需要学会更好地阅读。这是最干净的代码,它很好地利用了函数是第一类对象的事实。@unknown。很抱歉我可能会被器官收割机绑架,然后在写了X个月的手术后服用麻醉药的时候读代码。如果你公司的任何人都看不懂,那么他们靠写代码为生,而我却不懂,这让我很生气。这真的是很琐碎的东西。如果你要为尽可能低的分母编写代码,那么你总是会遇到这个问题,即使代码是可读的和Pythonic的。@Unknown:在某些时候,你真的必须假设对所使用的编程语言有基本的了解。如果代码使用了语言的某个深奥部分,您可以添加注释,但该代码并非完全不可读,而且我也不是一个python迷。@未知:字典可以这样使用是python的基本知识。局域网
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
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_)