太多的 if 语句

Too many if statements

我有一些话题要讨论。我有一个包含 24 ifs/elifs 的代码片段。 Operation 是我自己的 class,代表类似于 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个class然后用polymorphism比较好?我不相信它会让我的代码易于维护...一方面,这些 if 非常清楚,应该不难理解,另一方面,if 太多了s.

我的问题很笼统,但是我在 Python 中编写代码,所以我不能使用像 switch.

这样的结构

你怎么看?


更新:

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

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

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 的 class。

如果Operation.START等是可哈希的,可以使用字典,键为条件,值为函数调用,例子-

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

然后您可以执行此字典查找并调用函数,示例 -

d[operation]()

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].

的字典

这是一个混蛋 switch/case 使用字典完成的:

例如:

# 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,

}

然后调用等效的开关块:

options["string"]()

您可以对 getattr 使用一些内省:

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

假设操作是 "STATUS",它将被大写为 "Status",然后附加到 "Object",得到 "StatusObject"。然后将在 strategy_objects 上调用 StatusObject 方法,如果此属性不存在或不可调用,则会灾难性地失败。 :)(即添加错误处理。)

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

您可以尝试 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) 而不用这个函数。

从python3.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/