如何实现字典对象的“下一步”可迭代?

时间:2016-08-01 13:54:55

标签: python python-2.7 dictionary iterator iterable

我有一个字典的以下包装器:

class MyDict:
    def __init__(self):
        self.container = {}

    def __setitem__(self, key, value):
        self.container[key] = value

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

    def __iter__(self):
        return self

    def next(self):
        pass

dic = MyDict()
dic['a'] = 1
dic['b'] = 2

for key in dic:
    print key

我的问题是我不知道如何实现next方法使MyDict可迭代。任何意见,将不胜感激。

2 个答案:

答案 0 :(得分:10)

字典本身不是迭代器(只能通过迭代)。您通常将它们设为 iterable ,这是一个可以为其生成多个迭代器的对象。

完全删除next方法,每次调用__iter__时都返回一个可迭代对象。这可以简单到只返回self.container的迭代器:

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

如果您必须使您的班级成为迭代器,那么您必须以某种方式跟踪当前的迭代位置,并在您到达'结束时提升StopIteration ;。一个天真的实现可能是在第一次调用iter(self.container)时将self对象存储在__iter__上:

def __iter__(self):
    return self

def next(self):
    if not hasattr(self, '_iter'):
        self._iter = iter(self.container)
    return next(self._iter)

此时iter(self.container)对象负责跟踪迭代位置,并在到达结束时引发StopIteration。如果基础字典被更改(添加或删除了密钥)并且迭代顺序已被破坏,它也会引发异常。

另一种方法是每次只存储整数位置和索引到list(self.container),并且忽略插入或删除可以改变字典迭代顺序的事实:

_iter_index = 0

def __iter__(self):
    return self

def next(self):
    idx = self._iter_index
    if idx is None or idx >= len(self.container):
        # once we reach the end, all iteration is done, end of.
        self._iter_index = None
        raise StopIteration()
    value = list(self.container)[idx]
    self._iter_index = idx + 1
    return value

在这两种情况下,您的对象都是迭代器,只能通过迭代。到达终点后,您无法再次重新启动它。

答案 1 :(得分:2)

如果您希望能够在嵌套循环中使用类似dict的对象,或者需要在同一对象上进行多次迭代的任何其他应用程序,那么您需要实现一个返回的__iter__方法一个新创建的迭代器对象。

Python的可迭代对象都是这样做的:

>>> [1, 2, 3].__iter__()
<listiterator object at 0x7f67146e53d0>
>>> iter([1, 2, 3]) # A simpler equivalent
<listiterator object at 0x7f67146e5390>

对象'__iter__方法最简单的方法是在底层字典上返回一个迭代器,如下所示:

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

有关您可能需要的详细信息,请参阅this Github repository