python迭代类似dict的对象

标签 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__ 应该足以遍历我的测试类。事实上,当我尝试迭代它时,它并没有告诉我我不能,但是我遇到了一个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
  • 你知道这个 0 来自哪里吗?(背后发生了什么)

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

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

最佳答案

您在找到的文档中遗漏了一个关键措辞:

For sequence types, the accepted keys should be integers and slice objects. [...] [I]f of a value outside the set of indexes for the sequence (after any special interpretation of negative values), IndexError should be raised.

Note: for loops expect that an IndexError will be raised for illegal indexes to allow proper detection of the end of the sequence.

粗斜体强调是我的。如果您接受,而不是整数,您就没有序列。

Python 词汇表解释更多;查看definition of sequence :

An iterable which supports efficient element access using integer indices via the __getitem__() special method and defines a __len__() method that returns the length of the sequence. [...] Note that dict also supports __getitem__() and __len__(), but is considered a mapping rather than a sequence because the lookups use arbitrary immutable keys rather than integers.

所以序列接受整数索引,而这正是 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__ 方法时,那个调用 产生特殊的迭代器可用。

关于python迭代类似dict的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40630678/

相关文章:

python - 当函数退出时,对函数中的变量所做的更改将恢复

python - 在 Python 中合并相同键的字典

python - 从 Python Shell、IPython 控制台和脚本内部运行时 Next 函数的不同行为

java - 构建自定义迭代器

python - 通过 python 访问雷鸟电子邮件

Python无法用Supervisor读取环境变量

python - JSON KeyError 解析输入

python - 通过嵌套字典键获取唯一列表项

python - 在 R 中使用哈希包时,无法将类型 'closure' 强制转换为类型 'character' 的向量

python - 第一次只移动 zip Python 中两个迭代器中的一个