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

一个只定义了'\uu getitem\uuu'方法的类如何支持'in'运算符?

  •  2
  • adnanmuttaleb  · 技术社区  · 5 年前

    如果我有以下定义:

    Card = namedtuple('Card', ['rank', 'suit'])
    
    class CardDeck():
      ranks = [str(x) for x in range(2, 11)] + list('JQKA')
      suits = 'spades diamonds clubs hearts'.split()
    
      def __init__(self):
        self._cards = [Card(rank, suit) for rank in self.ranks for suit in self.suits]
    
      def __getitem__(self, index):
        return self._cards[index]
    

    怎么了 in 在没有 __contains__

    deck = CardDeck()
    print(Card('2', 'hearts') in deck)
    

    将输出:

    True
    

    有什么想法吗?

    2 回复  |  直到 5 年前
        1
  •  3
  •   Martijn Pieters    5 年前

    __getitem__ __contains__ __iter__ method Membership test operations section 表达 参考文件:

    __getitem__() x in y True 当且仅当存在非负整数索引 以至于 x is y[i] or x == y[i] ,并且没有较低的整数索引提高 IndexError 例外。

    实际上,Python只是使用了一个递增的索引,在Python中是这样的:

    from itertools import count
    
    def contains_via_getitem(container, value):
        for i in count():   # increments indefinitely
            try:
                item = container[i]
                if value is item or value == item:
                    return True
            except IndexError:
                return False
    

    这种处理方法扩展到所有迭代功能。未实现的容器 __iter公司__ 但一定要实施 __获取项目__ 仍然可以为它们创建迭代器(使用 iter() 或C-API等效物):

    >>> class Container:
    ...     def __init__(self):
    ...         self._items = ["foo", "bar", "baz"]
    ...     def __getitem__(self, index):
    ...         return self._items[index]
    ...
    >>> c = Container()
    >>> iter(c)
    <iterator object at 0x1101596a0>
    >>> list(iter(c))
    ['foo', 'bar', 'baz']
    

    当然,通过迭代进行的包容测试并不是真正有效的。如果有一种方法可以在没有完全扫描的情况下确定某个内容是否是容器中的项目,请实现 方法提供更好的实现!

    对于一副牌,我可以想象 是的 当项目是 Card 实例应该足够了(前提是 类验证等级和适应参数):

    def __contains__(self, item):
        # a card deck contains all possible cards
        return isinstance(item, Card)
    
        2
  •  2
  •   wwii    5 年前

    the documemtation

    object.__contains__(self, item)   ...
    
     For objects that don’t define __contains__(), the membership test
     first tries iteration via __iter__(), then the old sequence iteration
     protocol via __getitem__(),...
    

    see this section in the language reference .