python iter over dict-like object

时间:2016-11-16 11:12:15

标签: python dictionary iterator

 class Test(object):

     def __init__(self, store):
         assert isinstance(store, dict)
         self.store = store

     def __getitem__(self, key):
         return self.store[key]

我试着在这堂课上喋喋不休。在this doc中说,实现__getitem__应该足以胜过我的Test类。事实上,当我试图通过它时,它并没有告诉我我不能,但我有一个 KeyError

In [10]: a = Test({1:1,2:2})

In [11]: for i in a: print i
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-11-8c9c9a8afa41> in <module>()
----> 1 for i in a: print i

<ipython-input-9-17212ae08f42> in __getitem__(self, key)
      4         self.store = store
      5     def __getitem__(self, key):
----> 6         return self.store[key]
      7

KeyError: 0
  • 你知道这个来自哪里吗?(引擎盖下的内容)

我知道我可以通过添加__iter__函数来解决它:

def __iter__(self):
    return dict.__iter__(self.store)
  • 这是解决此问题的最佳方法吗?(我也可能会继承dict类)。

1 个答案:

答案 0 :(得分:7)

您错过了您找到的文档中的重要措辞:

  

对于 序列类型 ,接受的键应为整数和切片对象。 [...] [I] f除了序列 之外的值 (在对负值进行任何特殊解释之后) ,IndexError应该被提出。

     

注意for循环期望为非法索引引发IndexError以允许正确检测序列的结尾

大胆的斜体重点是我的。如果您接受而不是整数,则表示您没有序列。

Python词汇表解释更多;请参阅definition of sequence

  

一个iterable,它通过__getitem__()特殊方法 使用 整数索引支持有效的元素访问,并定义一个返回长度的__len__()方法序列。 [...] 请注意dict也支持__getitem__()__len__(),但它被视为映射而不是序列,因为查找使用任意不可变键而不是比整数。

因此序列接受整数索引,这正是for在迭代 * 时提供的。当给定一个迭代的对象时,如果除__getitem__之外没有其他方法可用,则构造一个特殊的迭代器,它从0开始并不断增加计数器直到IndexError被引发。在纯Python中,它是:

def getitem_iterator(obj):
    getitem = type(obj).__getitem__  # special method, so on the type
    index = 0
    try:
        while True:
            yield getitem(obj, index)
            index += 1
    except IndexError:
        # iteration complete
        return

实际实现在C中,请参阅PySeqIter_Type definition and functions

改为实施__iter__ method;它存在时使用。由于你包装了一个字典,你可以简单地返回该字典的迭代器(使用iter() function而不是直接调用特殊方法):

def __iter__(self):
    return iter(self.store)

* 从技术上讲,for不提供此功能。 for仅使用iter(obj),并且当没有__iter__方法可用时,调用生成特殊迭代器。