【问题标题】:Check for [] operator检查 [] 运算符
【发布时间】:2011-11-28 02:19:06
【问题描述】:

如何在 Python 中检查一个对象是否支持 [] 操作?我想到了类似的东西:

if supports(obj, ?[]?):
    print("Supports")  

【问题讨论】:

    标签: python


    【解决方案1】:

    您不会“检查支持”。您只需使用它:

    try:
        a = obj[whatever]
    except TypeError:
        # whatever your fall-back plan is when obj doesn't support [] (__getitem__) 
    

    编写自己的isinstance 总是错误的做法。不从集合 ABC 类继承的新类型仍然可以具有正确的行为。 Duck Typing 意味着您永远不能依赖 isinstance

    编写您自己的hasattr 测试只是重复了引发异常的Python 内部检查。既然 Python 必须进行测试,为什么要重复呢?

    最后,“我认为通过异常处理,这段代码的可读性会降低。”是假的。许多有经验的 Python 程序员接受的 Pythonic 原则是,请求许可更容易请求宽恕。

    该语言旨在执行此操作,但有例外。

    【讨论】:

    • +1。一般来说,我认为请求宽恕比请求许可更pythonic。
    • 确实,避免异常要好得多,因为它们的引发成本很高。
    • 恕我直言,如果您担心性能的这种微小下降,您不应该使用 Python。与 C 相比,它不是一种高性能的语言(从这里开始火焰战!)。另外... AttributeError 绝对是您可以在这里找到的东西,而不是 TypeError
    • 哇...我印象深刻。我刚刚运行了一组测试,通过异常捕获它是fast。甚至比测试__getitem__ 的否定案例还要快!我真的必须重新考虑如何在 Python 中使用异常......
    • Here 是我用来测试的代码。我猜是因为 Python 的解释性质,异常必须非常便宜。我将不得不根据 EAFP 重新考虑我的代码(并且可能会重新编写一些代码)。今天肯定学到了一些东西。
    【解决方案2】:

    试试hasattr(obj, "__getitem__")

    if hasattr(obj, "__getitem__"):
        print("Supports") 
    

    来自operator.getitem 帮助:

    operator.getitem??
    Type:           builtin_function_or_method
    Base Class:     <type 'builtin_function_or_method'>
    String Form:    <built-in function getitem>
    Namespace:      Interactive
    getitem(a, b) -- Same as a[b].
    

    查看operator module

    • 返回索引 b 处 a 的值:

      operator.getitem(a, b)
      operator.__getitem__(a, b)
      
    • 将a的切片从索引b返回到索引c-1:

      operator.getslice(a, b, c)
      operator.__getslice__(a, b, c)
      
    • 将索引 b 处的 a 的值设置为 c:

      operator.setitem(a, b, c)
      operator.__setitem__(a, b, c)
      
    • 将a的切片从索引b到索引c-1设置为序列v。

      operator.setslice(a, b, c, v)
      operator.__setslice__(a, b, c, v)
      
    • 删除索引 b 处 a 的值:

      operator.delitem(a, b)
      operator.__delitem__(a, b)
      
    • 从索引b到索引c-1删除a的切片:

      operator.delslice(a, b, c)
      operator.__delslice__(a, b, c)
      

    等等。

    【讨论】:

      【解决方案3】:

      [] 运算符的内部名称是 __getitem__(和 __setitem__),因此您可以通过以下方式进行很好的尝试:

      if hasattr(obj, '__getitem__'):
          print "Supports"
      

      【讨论】:

      • 如果你在乎,是的。例如,tuple 不支持 __setitem____delitem__
      【解决方案4】:

      根据language docs,您可以检查该类是否具有__getitem__ 方法。

      【讨论】:

        【解决方案5】:

        有一种简单的方法可以查看您是否可以迭代对象(即,执行for i in obj):

        import collections
        if isinstance(obj, collections.Iterable):
            print 'obj supports iteration'
        

        如果您担心是否可以使用实际密钥,我建议您只“请求宽恕”而不是许可:

        try:
            value = obj[key]
        except (AttributeError, TypeError, IndexError):
            # These are different things that can return in different situations
            value = None
            print 'I guess that key doesn\'t work'
        

        我建议使用collections.Iterable 而不是这种方法的唯一原因是,在你的for 周围有一个try 循环,谁知道还有什么,可能会有点复杂。

        【讨论】:

        • 能够使用[] 运算符与对象是否可迭代没有任何关系。您正在寻找collections.Sequence,这相当于检查__getitem__
        • @agf,你当然是对的,但我认为这可能是 OP 试图弄清楚的(这就是我通常要检查的)。
        • 如果我是 Python 新手并询问有关迭代的问题,我可能会问“我如何检查对象是否支持 in”,因为这是您第一次学习 Python 中迭代的方式,for item in obj:,不是关于[],但我可以看看你是否还在用 C 语法思考这有什么意义。
        猜你喜欢
        • 1970-01-01
        • 2021-10-27
        • 2015-07-28
        • 2023-04-07
        • 1970-01-01
        • 2014-08-10
        • 2021-10-29
        • 2016-08-02
        • 2016-06-25
        相关资源
        最近更新 更多