13

我有一些话题要讨论。我有一段 24if秒/elif秒的代码。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 个类并使用多态会更好吗?我不相信它会使我的代码可维护......一方面这些ifs 非常清楚,应该不难理解,另一方面有太多ifs。

我的问题相当笼统,但是我正在用 Python 编写代码,所以我不能使用switch.

你怎么看?


更新

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

4

7 回答 7

18

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

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

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

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

或者使用字典的get方法,如果未找到您提供的键,则允许您指定默认值。

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

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

于 2015-07-31T14:30:55.013 回答
3

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 语句更好地扩展。请注意,如果您没有 else 案例要处理,您可以直接使用字典operation_dispatcher[operation]

于 2015-07-31T14:32:14.923 回答
2

你可以试试这样的。

例如:

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) 而不使用该函数。

于 2015-07-31T14:37:01.353 回答
1

您可以使用一些自省getattr

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

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

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

于 2015-07-31T14:36:26.840 回答
0

如果Operation.START, etc 是可散列的,则可以使用带有键的字典作为条件,将值作为要调用的函数,例如 -

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

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

d[operation]()
于 2015-07-31T14:32:03.983 回答
0

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

于 2021-10-25T13:02:08.627 回答
-1

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

例如:

# 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"]()
于 2015-07-31T14:32:34.193 回答