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

问题描述

我有以下字典包装器:

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 可迭代.任何意见,将不胜感激.

My problem is that I don't know how to implement the next method to make MyDict iterable. Any advice would be appreciated.


解决方案

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

Dictionaries are themselves not an iterator (which can only be iterated over once). You usually make them an iterable, an object for which you can produce multiple iterators instead.

完全删除 next 方法,并让 __iter__ 在每次调用时返回一个可迭代对象.这可以像返回 self.container 的迭代器一样简单:

Drop the next method altogether, and have __iter__ return an iterable object each time it is called. That can be as simple as just returning an iterator for self.container:

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

如果你必须让你的类成为一个迭代器,你必须以某种方式跟踪当前的迭代位置并在到达结束"时提高 StopIteration.一个简单的实现可能是在第一次调用 __iter__ 时将 iter(self.container) 对象存储在 self 上:

If you must make your class an iterator, you'll have to somehow track a current iteration position and raise StopIteration once you reach the 'end'. A naive implementation could be to store the iter(self.container) object on self the first time __iter__ is called:

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.如果底层字典被更改(添加或删除键)并且迭代顺序被破坏,它也会引发异常.

at which point the iter(self.container) object takes care of tracking iteration position for you, and will raise StopIteration when the end is reached. It'll also raise an exception if the underlying dictionary was altered (had keys added or deleted) and iteration order has been broken.

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

Another way to do this would be to just store in integer position and index into list(self.container) each time, and simply ignore the fact that insertion or deletion can alter the iteration order of a dictionary:

_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

在这两种情况下,您的对象都是一个迭代器,只能迭代一次.一旦到达终点,就不能再重新开始了.

In both cases your object is then an iterator that can only be iterated over once. Once you reach the end, you can't restart it again.

相关文章