【问题标题】:Dictionary or If statements, Jython字典或 If 语句,Jython
【发布时间】:2010-09-21 15:13:49
【问题描述】:

我现在正在编写一个脚本,它将使用 dom4j 从 HTML 中获取某些信息。

由于 Python/Jython 没有原生 switch 语句,我决定使用一大堆调用适当方法的 if 语句,如下所示:

if type == 'extractTitle':
    extractTitle(dom)
if type == 'extractMetaTags':
    extractMetaTags(dom)

我将根据我想从 HTML 中提取的信息添加更多内容,并考虑采用我在本网站其他地方找到的字典方法,示例如下:

{
    'extractTitle':    extractTitle,
    'extractMetaTags': extractMetaTags
}[type](dom)

我知道每次运行脚本时都会构建字典,但同时如果我要使用 if 语句,脚本必须检查所有这些语句,直到它击中正确的一个。我真正想知道的是,哪一个表现更好或通常是更好的做法?

更新: @Brian - 感谢您的精彩回复。我有一个问题,如果任何提取方法需要多个对象,例如

handle_extractTag(self, dom, anotherObject)
# Do something

您将如何对 handle 方法进行适当的更改来实现这一点?希望你明白我的意思:)

干杯

【问题讨论】:

    标签: python switch-statement jython


    【解决方案1】:

    为了避免在 dict 中指定标签和处理程序,您可以只使用一个处理程序类,其中的方法命名为匹配类型。例如

    class  MyHandler(object):
        def handle_extractTitle(self, dom):
            # do something
    
        def handle_extractMetaTags(self, dom):
            # do something
    
        def handle(self, type, dom):
            func = getattr(self, 'handle_%s' % type, None)
            if func is None:
                raise Exception("No handler for type %r" % type)
            return func(dom)
    

    用法:

     handler = MyHandler()
     handler.handle('extractTitle', dom)
    

    更新:

    当您有多个参数时,只需更改句柄函数以获取这些参数并将它们传递给函数。如果您想让它更通用(这样您在更改参数签名时不必同时更改处理程序函数和句柄方法),您可以使用 *args 和 **kwargs 语法来传递所有接收到的参数.然后handle方法就变成了:

    def handle(self, type, *args, **kwargs):
        func = getattr(self, 'handle_%s' % type, None)
        if func is None:
            raise Exception("No handler for type %r" % type)
        return func(*args, **kwargs)
    

    【讨论】:

    • 当然,现在解释器必须构建一个类(因此是一个 dict)及其方法而不是 dict :) 不过不用担心:dicts 是 python 的基础,因此非常优化
    • dispatch dict 是类的一部分,它只会被构造一次。您也可以避免只使用同一个实例来构造实例,或者直接使用类或静态方法(尽管我怀疑速度差异会不会很明显)。
    • 动态语言可以做什么的一个很好的例子。如果她能像这样完成这件事,谁会想要一个“开关”。还遵守 DRY 原则,将信息保存在一个地方,并且可以通过子类轻松扩展。荣誉
    • 这是一个非常重要的 Python 设计模式。
    【解决方案2】:

    效率问题几乎无关紧要。字典查找是通过一种简单的散列技术完成的,if 语句必须一次评估一个。字典往往更快。

    我建议您实际上拥有从 DOM 中提取的多态对象。

    目前尚不清楚type 是如何设置的,但它确实看起来可能是一系列相关对象,而不是简单的字符串。

    class ExtractTitle( object ):
        def process( dom ):
            return something
    
    class ExtractMetaTags( object ):
        def process( dom ):
            return something
    

    您可以这样做,而不是设置 type="extractTitle"。

    type= ExtractTitle() # or ExtractMetaTags() or ExtractWhatever()
    type.process( dom )
    

    那么,您将不会构建这个特定的字典或 if 语句。

    【讨论】:

      【解决方案3】:

      使用您的代码,您运行的所有函数都会被调用。

      处理程序 = { “提取标题”:提取标题, 'extractMetaTags':提取MetaTags } 处理程序[类型](dom)

      会像您原来的 if 代码一样工作。

      【讨论】:

        【解决方案4】:

        您对字典的使用不太正确。在您的实现中,所有方法都将被调用,所有无用的方法都将被丢弃。通常做的更像是:

        switch_dict = {'extractTitle': extractTitle, 
                       'extractMetaTags': extractMetaTags}
        switch_dict[type](dom)
        

        如果您有大量(或可变的)项目,那么这种方式更重要且更具可扩展性。

        【讨论】:

        • 方法不会被调用(即“运行”、“执行”、“评估”...)只是被列为字典表达式中的值。您可能要指出的是,OP 会为每次调用重建字典一次,这 浪费的。
        • 不,自从我回答后,OP 改变了它的帖子。在第一个版本中,方法实际上被调用了。
        【解决方案5】:

        这取决于我们讨论了多少个 if 语句;如果它是一个非常小的数字,那么它会比使用字典更有效。

        但是,与往常一样,我强烈建议您做任何使您的代码看起来更干净的事情,直到经验和分析告诉您需要优化特定的代码块。

        【讨论】:

        • 我还没有编写脚本,但如果我要使用 if 语句,我将编写超过 20 个 if 语句。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-06
        • 1970-01-01
        • 2013-04-02
        • 2021-11-15
        • 2018-03-27
        • 1970-01-01
        相关资源
        最近更新 更多