【问题标题】:python iter over dict-like objectpython iter over dict-like object
【发布时间】:2017-03-30 13:34:26
【问题描述】:
 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
  • 你知道这个 0 是从哪里来的吗?(幕后发生了什么)

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

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

【问题讨论】:

  • 解决什么问题的最佳方法,该类应该做什么?类只有dict 值?

标签: python dictionary iterator


【解决方案1】:

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

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

注意for 循环期望为非法索引引发 IndexError,以便正确检测序列的结尾强>。

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

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

一个支持使用通过__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__ 方法时,调用会产生特殊的迭代器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-29
    • 2020-03-25
    • 2021-08-18
    • 2021-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多