代码之家  ›  专栏  ›  技术社区  ›  batbrat

在Python字典或if-else中选择不同的开关大小写替换?

  •  19
  • batbrat  · 技术社区  · 16 年前

    我最近阅读了一些问题,建议不要在支持switch case语句的语言中使用它。就Python而言,我已经看到了许多switch case替换,例如:

    1. 使用词典(多种变体)
    2. 使用函数装饰器( http://code.activestate.com/recipes/440499/ )
    3. 使用if-elif-else梯形图

    考虑到选项的多样性,我很难决定如何处理特定的代码。我想了解选择其中一种方法而不是另一种方法的一般标准。此外,如果我在做出决定时遇到困难,我希望得到建议(并解释选择)。

    具体问题如下:

    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插槽 响应于从菜单中选择绘制曲线。一旦应用程序完成,上述方法将包含总共4-7条曲线。在这种情况下使用一次性词典合理吗?既然最明显的方法是如果elif else,我应该坚持下去吗?我也考虑在这里使用**kargs(在朋友的帮助下),因为所有的曲线类都使用**karg。。。


    第二段代码是 qt插槽

    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  
    

    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等在构造函数中初始化。

    据我所知,选择字典的原因是为了快速查找。什么时候有理由这样做?当我有100个或更多病例时?每次调用函数时,继续构建并丢弃字典是个好主意吗?如果我在函数外为此目的构建一个dict,我应该检查其他地方是否需要它吗?如果其他地方不需要它怎么办?

    如果elif else ,何时使用其他选项?

    7 回复  |  直到 16 年前
        1
  •  24
  •   S.Lott    16 年前

    叹气。对问题的错误部分过于纠结。switch语句不是问题所在。表达“替代”的方式有很多,但并不增加 意义 .

    问题是 意义 --不是技术声明选择。

    有三种常见的模式。

    • 将密钥映射到对象 意思是 :您的“条件”是映射到对象的简单静态键值。

    • 子类之间的变异行为

    • 其他变体行为 .使用if-elif-else梯子。当您没有基本静态的键值映射时,请使用此选项。当条件复杂时,或者您 意思是 程序,而不是对象。

    其他一切都只是可以实现类似结果的棘手代码。

    使用Tuple。这只是一本没有映射的字典。这需要搜索,应尽可能避免搜索。不要这样做,效率很低。使用字典。

    http://code.activestate.com/recipes/440499/ ).冰。这掩盖了你正在解决的问题的if-elif-elif性质。不要这样做,选择并不明显 独家

    访客 图案。当您有一个对象跟在后面时,请使用此选项 复合

        2
  •  8
  •   dF.    16 年前

    在第一个例子中,我当然会坚持if-else语句。事实上,我认为没有理由不使用if-else,除非

    1. 您发现(例如使用配置文件模块)if语句是一个瓶颈(除非您有大量案例,但收效甚微,否则IMO不太可能)

    2. 使用字典的代码更清晰/重复更少。

    你的第二个例子,我实际上会重写

    setattr(self, name, value)
    

        3
  •  2
  •   unwind    16 年前

    考虑到这是对用户操作(从菜单中选择内容)的响应,并且您预期的选择数量非常少,我肯定会选择一个简单的if-elif-else梯形图。

    对速度进行优化是没有意义的,因为无论如何,它只会在用户做出选择时发生,这不是“光线跟踪器的内环”领域。当然,给用户快速反馈很重要,但由于病例数量很少,也没有危险。

    为了简洁而优化是没有意义的,因为(imo更清晰,零可读性开销)if梯形图无论如何都会很短。

        4
  •  2
  •   joel.neely    16 年前

    1. 另一个问题是可维护性。具有字符串->curveFunction字典允许您对菜单进行数据驱动。然后添加另一个选项只是添加另一字符串的问题->字典中的函数条目(位于专用于配置的代码部分中)。

    2. 即使你只有几个条目,它也会“分离关注点”; _setCurrentCurve 负责运行时的接线,而不是定义组件箱。

    3. 建立字典并保留它。

    4. 即使它没有在其他地方使用,您也可以获得上述好处(可定位性、可维护性)。

    我的经验法则是对代码的每个组件问“这里发生了什么?”。如果答案是以下形式

    ... ... ...

    (如“定义函数库 将每个与菜单中的一个值相关联”),那么有一些问题需要分开。

        5
  •  1
  •   alexpopescu    16 年前

    每个暴露的选项都很适合某些场景:

    1. if elif else:简洁明了
    2. tuple:每个分支都有多个选择,比if-else简单。
    3. 多态性:自动面向对象分支
    4. 等等

    ./亚历克斯

        6
  •  1
  •   kquinn    16 年前

    我同意df关于第二个例子的看法。第一个例子,我可能会尝试使用字典重写,特别是如果所有曲线构造函数都有相同的类型签名(可能使用*args和/或**kwargs)。有点像

    def _setCurrentCurve(self, new_curve):
        self.currentCurve = self.preset_curves[new_curve](options_here)
    

    或者甚至

    def _setCurrentCurve(self, new_curve):
        self.currentCurve = self.preset_curves[new_curve](**preset_curve_defaults[new_curve])
    
        7
  •  1
  •   S.Lott    16 年前

    在Python中,不要考虑如何替换switch语句。

    请改用类和多态性。尽量将每个可用选项的信息以及如何在一个地方实现它(即实现它的类)。

    否则,你最终会有很多地方,每个地方都包含每个选择的一小部分,更新/扩展将是一场维护噩梦。

    这正是面向对象设计试图通过抽象、信息隐藏、多态和批量来解决的问题。