【问题标题】:Too many if statementsif 语句过多
【发布时间】:2015-07-31 14:27:40
【问题描述】:

我有一些话题要讨论。我有一段代码有 24 个ifs/elifs。 Operation 是我自己的类,代表类似于Enum 的功能。
这是一段代码:

if operation == Operation.START:
    strategy = strategy_objects.StartObject()
elif operation == Operation.STOP:
    strategy = strategy_objects.StopObject()
elif operation == Operation.STATUS:
    strategy = strategy_objects.StatusObject()
(...)

从可读性的角度来看,我有一些顾虑。将其更改为 24 类并使用polymorphism 会更好吗?我不相信它会使我的代码可维护......一方面,那些ifs 很清楚,应该不难理解,另一方面有太多ifs。

我的问题很笼统,但是我用 Python 编写代码,所以我不能使用像 switch 这样的结构。

你怎么看?


更新

重要的一点是StartObject()StopObject()StatusObject() 是构造函数,我想将一个对象分配给strategy 引用。

【问题讨论】:

  • case 声明,而不是?或者有一组方法引用来动态调用,例如任何与array_of_methods[operation]() 对应的python 都将是...
  • Marc,python 没有 switch/case 语句。 python.org/dev/peps/pep-3103

标签: python if-statement conditional code-readability code-maintainability


【解决方案1】:

您可能会使用字典。字典存储引用,这意味着函数完全可以使用,如下所示:

operationFuncs = {
    Operation.START: strategy_objects.StartObject
    Operation.STOP: strategy_objects.StopObject
    Operation.STATUS: strategy_objects.StatusObject
    (...)                  
}

最好有一个默认操作以防万一,所以当你运行它时使用try except 并处理异常(即相当于你的else 子句)

try:
    strategy = operationFuncs[operation]()
except KeyError:
    strategy = strategy_objects.DefaultObject()

或者使用字典的get 方法,如果找不到您提供的键,您可以指定默认值。

strategy = operationFuncs.get(operation(), DefaultObject())

请注意,将它们存储在字典中时不包括括号,只需在调用字典时使用它们。这也要求 Operation.START 是可散列的,但应该是这样,因为您将其描述为类似于 ENUM 的类。

【讨论】:

    【解决方案2】:

    Python 相当于 switch 语句的是使用字典。本质上,您可以像存储案例一样存储密钥,而值就是针对该特定案例所调用的值。因为函数是 Python 中的对象,所以您可以将它们存储为字典值:

    operation_dispatcher = {
        Operation.START: strategy_objects.StartObject,
        Operation.STOP: strategy_objects.StopObject,
    }
    

    然后可以按如下方式使用:

    try:
        strategy = operation_dispatcher[operation] #fetch the strategy
    except KeyError:
        strategy = default #this deals with the else-case (if you have one)
    strategy() #call if needed
    

    或者更简洁:

    strategy = operation_dispatcher.get(operation, default)
    strategy() #call if needed
    

    这可能比一堆 if-else 语句更好地扩展。请注意,如果您没有其他情况需要处理,您可以直接使用字典与operation_dispatcher[operation]

    【讨论】:

      【解决方案3】:

      你可以试试this

      例如:

      def chooseStrategy(op):
          return {
              Operation.START: strategy_objects.StartObject
              Operation.STOP: strategy_objects.StopObject
          }.get(op, strategy_objects.DefaultValue)
      

      这样称呼

      strategy = chooseStrategy(operation)()
      

      这个方法的好处是提供了一个默认值(就像一个最终的 else 语句)。当然,如果你只需要在代码中的一个地方使用这个决策逻辑,你总是可以使用 strategy = dictionary.get(op, default) 而不使用该函数。

      【讨论】:

      • 您错过了通话。 strategy = chooseStrategy(operation)()
      • 谢谢!我错过了他正在调用选择的策略。我已经编辑了我的帖子。
      【解决方案4】:

      从 python 3.10 开始

      match i:
          case 1:
              print("First case")
          case 2:
              print("Second case")
          case _:
              print("Didn't match a case")
      

      https://pakstech.com/blog/python-switch-case/

      【讨论】:

        【解决方案5】:

        你可以对getattr进行一些内省:

         strategy = getattr(strategy_objects, "%sObject" % operation.capitalize())()
        

        假设操作是“STATUS”,它将大写为“Status”,然后添加到“Object”前面,给出“StatusObject”。然后将在 strategy_objects 上调用 StatusObject 方法,如果此属性不存在或不可调用,则会发生灾难性的失败。 :)(即添加错误处理。)

        但字典解决方案可能更灵活。

        【讨论】:

        • 使用 hasattr(...) 检查类是否存在相当于字典解决方案中的 KeyError。
        【解决方案6】:

        如果Operation.START等是可散列的,你可以使用字典,键作为条件,值作为调用的函数,例如-

        d = {Operation.START: strategy_objects.StartObject , 
             Operation.STOP: strategy_objects.StopObject, 
             Operation.STATUS: strategy_objects.StatusObject}
        

        然后你可以做这个字典查找并调用函数,示例-

        d[operation]()
        

        【讨论】:

          【解决方案7】:

          这是一个使用字典完成的混蛋开关/案例:

          例如:

          # define the function blocks
          def start():
              strategy = strategy_objects.StartObject()
          
          def stop():
              strategy = strategy_objects.StopObject()
          
          def status():
              strategy = strategy_objects.StatusObject()
          
          # map the inputs to the function blocks
          options = {"start" : start,
                     "stop" : stop,
                     "status" : status,
          
          }
          

          然后调用等效的 switch 块:

          options["string"]()
          

          【讨论】:

          • 但是strategy 将是每个小函数的本地,并且不会在您执行options["string"]() 的范围内可见。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-04-25
          • 2012-01-08
          相关资源
          最近更新 更多