太多的 if 语句
Too many if statements
我有一些话题要讨论。我有一个包含 24 if
s/elif
s 的代码片段。 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")
我有一些话题要讨论。我有一个包含 24 if
s/elif
s 的代码片段。 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")