【问题标题】:"Pythonic" equivalent for handling switch and multiple string compares用于处理开关和多字符串比较的“Python”等效项
【发布时间】:2010-10-13 02:11:40
【问题描述】:

好吧,所以我的标题很烂。一个例子效果更好:

input = 'check yahoo.com'

我想解析输入,使用第一个单词作为“命令”,将字符串的其余部分作为参数。这是我的非 Python 思维如何编码的简单版本:

if len(input) > 0:
    a = input.split(' ')
    if a[0] == 'check':
        if len(a) > 1:
            do_check(a[1])
    elif a[0] == 'search':
        if len(a) > 1:
            do_search(a[1])

我喜欢 Python,因为它将通常复杂的事情变成了相当简单的事情。我对它不是很有经验,而且我相当肯定有更好的方法来做这些事情......更像pythonic。我见过一些人用 dicts 和 lambda 函数替换 switch 语句的例子,而其他人只是推荐 if..else 嵌套。

【问题讨论】:

标签: conditional python


【解决方案1】:
dispatch = {
  'check': do_check,
  'search': do_search,
}
cmd, _, arg = input.partition(' ')
if cmd in dispatch:
    dispatch[cmd](arg)
else:
    do_default(cmd, arg)

【讨论】:

  • 而不是 do_default 那里,您可能希望在调度中执行 if a[0] 并将 a[0] 传递给默认值,或者简单地将 do_default 替换为 lambda arg:do_default(a [0], arg) -- 这样你就可以通过命令了。
  • 你可以将最后四行替换为:dispatch.get(cmd, do_default)(arg)
  • @John:这样 do_default 不会得到 cmd。
  • 所以将最后 4 行替换为: dispatch.get(cmd, lambda a:do_default(cmd, a))(arg) 现在 do_default 接收 'cmd'。
  • @Abgan:我考虑过这一点,但我认为明确的 if 语句看起来比 lambda 更好。 (或 functools.partial )
【解决方案2】:

我相当肯定有更好的方法来做这些事情......某种方式更pythonic。

不是真的。您的代码简单、清晰、明显且类似于英语。

我见过一些用 dicts 和 lambda 函数替换 switch 语句的例子,

是的,您已经看过它们,但它们并不清晰、不明显或类似英语。它们的存在是因为有些人喜欢在 switch 语句上绞尽脑汁。

而其他人只是推荐 if..else 巢。

正确。他们工作。它们简单、清晰、...

你的代码很好。不要管它。继续前进。

【讨论】:

    【解决方案3】:

    这可以让您避免给每个命令名称两次;函数名几乎直接用作命令名。

    class CommandFunctions:
        def c_check(self, arg):
            print "checking", arg
    
        def c_search(self, arg):
            print "searching for", arg
    
        def c_compare(self, arg1, arg2):
            print "comparing", arg1, "with", arg2
    
        def execute(self, line):
            words = line.split(' ')
            fn = getattr(self, 'c_' + words[0], None)
            if fn is None:
                import sys
                sys.stderr.write('error: no such command "%s"\n' % words[0])
                return
            fn(*words[1:])
    
    cf = CommandFunctions()
    import sys
    for line in sys.stdin:
        cf.execute(line.strip())
    

    【讨论】:

    • 使用错误处理方法作为 gettr 的默认值(而不是 None)会更好,因此您不必显式检查未知命令
    • 我想过这样做,但是被调用的函数没有得到单词[0],因此它无法在错误消息中打印未知命令。
    【解决方案4】:

    如果您正在寻找一种单一的“pythonic”方法,您可以使用以下方法:

    
    def do_check(x): print 'checking for:', x
    def do_search(x): print 'searching for:', x
    
    input = 'check yahoo.com'
    {'check': do_check}.get(input.split()[0], do_search)(input.split()[1])
    # checking for: yahoo.com
    
    input = 'search google.com'
    {'check': do_check}.get(input.split()[0], do_search)(input.split()[1])
    # searching for: google.com
    
    input = 'foo bar.com'
    {'check': do_check}.get(input.split()[0], do_search)(input.split()[1])
    # searching for: bar.com
    

    【讨论】:

    • 嗯,它当然不会简化 Tom 的示例,但它需要他的 8 行代码,并且只用一行代码就可以完成同样的事情。
    • 第二次看,他使用了 elif。我一开始以为他用了一个else。我需要修改我的代码。很抱歉造成混乱。
    • 老兄,这是大错特错。你的字典只有“检查”,好像需要一本字典来在“检查”和“搜索”之间进行选择,因为“如果”语句是不够的!
    • 这太复杂了。如果我看到这段代码,我肯定会把头发拉出来。看在上帝的份上,这只是一个“if elif”构造。
    • 嘿,没那么糟!您可以使用任意数量的命令来扩展字典,在 {}.get() 中保留一个默认值(可能不是 do_search,而是一些错误处理程序) - 它仍然比 if-elif-elif-... 更紧凑。 -else 构造。
    【解决方案5】:

    忽略,我刚刚意识到我的答案与其他答案之一相似 - 显然没有删除键:)

    【讨论】:

      【解决方案6】:

      @MizardX's answer 的变化:

      from collections import defaultdict
      
      dispatch = defaultdict(do_default, check=do_check, search=do_search)
      cmd, _, arg = input.partition(' ')
      dispatch[cmd](arg)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-15
        • 1970-01-01
        • 2020-08-17
        • 2022-09-23
        • 2014-06-03
        • 2017-11-23
        • 2023-04-09
        • 1970-01-01
        相关资源
        最近更新 更多