在 Python 中选择不同的 switch-case 替换 - 字典还是 if-elif-else?
问题描述
我最近阅读了建议不要在支持它的语言中使用 switch-case 语句的问题.就 Python 而言,我已经看到了许多 switch case 替换,例如:
I recently read the questions that recommend against using switch-case statements in languages that do support it. As far as Python goes, I've seen a number of switch case replacements, such as:
- 使用字典(许多变体)
- 使用元组
- 使用函数装饰器(http://code.activestate.com/recipes/440499/)
- 使用多态(推荐方法而不是类型检查对象)
- 使用 if-elif-else 阶梯
- 甚至有人推荐了访问者模式(可能是外部的)
鉴于选项的多样性,我在决定对特定代码段执行什么操作时有些困难.我想了解在一般情况下选择其中一种方法而不是另一种方法的标准.此外,如果我无法做出决定(附上对选择的解释),我将不胜感激有关如何处理的建议.
Given the wide variety of options, I am having a bit of difficulty deciding what to do for a particular piece of code. I would like to learn the criteria for selecting one of these methods over the other in general. In addition, I would appreciate advice on what to do in the specific cases where I am having trouble deciding (with an explanation of the choice).
具体问题如下:
(1)
Here is the specific problem:
(1)
def _setCurrentCurve(self, curve):
if curve == "sine":
self.currentCurve = SineCurve(startAngle = 0, endAngle = 14,
lineColor = (0.0, 0.0, 0.0), expansionFactor = 1,
centerPos = (0.0, 0.0))
elif curve == "quadratic":
self.currentCurve = QuadraticCurve(lineColor = (0.0, 0.0, 0.0))
qt-slot 调用此方法以响应选择从菜单中绘制曲线.一旦申请完成,上述方法将包含总共 4-7 条曲线.在这种情况下使用一次性字典是否合理?由于最明显的方法是 if-elif-else,我应该坚持吗?我还考虑在这里使用 **kargs(在朋友的帮助下),因为所有曲线类都使用 **kargs...
This method is called by a qt-slot in response to choosing to draw a curve from a menu. The above method will contain a total of 4-7 curves once the application is complete. Is it justified to use a throw away dictionary in this case? Since the most obvious way to do this is if-elif-else, should I stick with that? I have also consider using **kargs here (with a friends help) since all the curve classes use **kargs...
(2)
第二段代码是一个 qt-slot,当用户更改曲线的属性时会调用它.基本上,插槽从 gui (spinBox) 中获取数据并将其放入适当曲线类的实例变量中.在这种情况下,我又遇到了同样的问题——我应该使用字典吗?
(2)
This second piece of code is a qt-slot that is called when the user changes a property of a curve. Basically the slot takes the data from the gui (spinBox) and puts it in an instance variable of the appropriate curve class. In this case, I again have the same question - should I use a dict?
这是前面提到的槽-
def propertyChanged(self, name, value):
"""A Qt slot, to react to changes of SineCurve's properties."""
if name == "amplitude":
self.amplitude = value
elif name == "expansionFactor":
self.expansionFactor = value
elif name == "startAngle":
self.startAngle = value
elif name == "endAngle":
self.endAngle = value
供参考,这里是连接到上述插槽的代码 -
For reference, here is the code for connecting to the above slot -
def _connectToPage(self, page):
for connectionData in page.getConnectibles():
self.connect(connectionData["object"],
SIGNAL(connectionData["signal"]),
lambda value, name = connectionData["property"]:
self.currentCurve.propertyChanged(name, value))
self.connect(connectionData["object"],
SIGNAL(connectionData["signal"]),
self.hackedDisplayArea.update)
注意 - self.endAngle 等在构造函数中初始化.
Note - The self.endAngle etc. are initialized in the constructor.
据我所知,选择 dict 的原因是为了快速查找.什么时候有保证?当我有 100 个或更多案例时?每次调用函数时继续构建和丢弃字典是个好主意吗?如果我在函数之外为此目的构建一个字典,我应该检查是否在其他地方需要它?如果其他地方不需要它会怎样?
As far as I know, the reasons for choosing a dict is for fast lookup. When is that warranted? when I have 100 cases or more? Is it a good idea to keep building and throwing away a dictionary each time the function is called? If I build a dict for this purpose outside a function, should I check If it is needed elswhere? What happens if it is not needed elsewhere?
我的问题是最好的做法是什么?做事最好/最优雅的方式是什么?换句话说,什么时候使用 if-elif-else,什么时候使用其他选项?
My question is what is the best-practice if there is one? What is the best/most elegant way to go about things? Put in yet another way, when to use if-elif-else, when to use each of the other options?
解决方案
叹息.对问题的错误部分过多地绞尽脑汁.switch 语句不是问题.有许多表达另类"的方式不添加意义.
Sigh. Too much hand-wringing over the wrong part of the problem. The switch statement is not the issue. There are many ways of expressing "alternative" that don't add meaning.
问题在于意义——而不是技术声明选择.
The issue is meaning -- not technical statement choices.
共有三种常见模式.
将键映射到对象.如果字典几乎是完全静态的,并且您在一个简单的键和另一个更复杂的东西之间有一个映射,请使用它.每次需要时都在运行中构建字典是愚蠢的.如果是意思,您可以使用它:您的条件"是映射到对象的简单静态键值.
Mapping a key to an object. Use a dictionary if it is almost totally static and you have a mapping between a simple key and another more complex thing. Building a dictionary on the fly each time you need it is silly. You can use this if it's what you mean: your "conditions" are simple, static key values that map to objects.
子类之间的变体行为.使用多态而不是类型检查对象.正确的.如果您在多个具有不同行为的类中有类似的对象,它们应该是多态的.尽可能多地使用它.
Variant behavior among subclasses. Use Polymorphism instead of type checking objects. Correct. If you have similar objects in multiple classes with variant behavior, they should be polymorphic. Use this as often as possible.
其他变体行为.使用 if-elif-else 阶梯.当您没有大量静态的键值映射时使用它.当条件复杂或您指过程而非对象时使用此选项.
Other variant behavior. Use an if-elif-else ladder. Use this when you don't have largely static key-to-value mapping. Use this when the conditions are complex, or you mean procedures, not objects.
其他一切都只是可以达到类似结果的棘手代码.
Everything else is just tricky code that can achieve similar results.
使用元组.这只是没有映射的字典.这需要搜索,并且应尽可能避免搜索.不要这样做,效率低下.使用字典.
Using a Tuple. This is just dictionary without the mapping. This requires search, and search should be avoided whenever possible. Don't do this, it's inefficient. Use a dictionary.
使用函数装饰器(http://code.activestate.com/recipes/440499/一个>).恶心.这隐藏了您正在解决的问题的 if-elif-elif 本质.不要这样做,选择是排他性的并不明显.使用其他任何东西.
Using a function decorator (http://code.activestate.com/recipes/440499/). Icky. This conceals the if-elif-elif nature of the problem you're solving. Don't do this, it isn't obvious that the choices are exclusive. Use anything else.
甚至有人推荐了 Visitor 模式.当您有一个遵循 Composite 设计模式的对象时使用它.这取决于多态性的工作,所以它并不是一个真正不同的解决方案.
Someone even recommended the Visitor pattern. Use this when you have an object which follows the Composite design pattern. This depends on polymorphism to work, so it's not really a different solution.
相关文章