【问题标题】:How to implement "next" for a dictionary object to be iterable?如何实现字典对象的“下一个”是可迭代的?
【发布时间】:2016-12-06 15:29:11
【问题描述】:

我有以下字典包装器:

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

【问题讨论】:

    标签: python python-2.7 dictionary iterator iterable


    【解决方案1】:

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

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

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

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

    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
    

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

    【讨论】:

      【解决方案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

      【讨论】:

        猜你喜欢
        • 2010-09-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-22
        • 1970-01-01
        • 2023-03-07
        • 2019-11-09
        相关资源
        最近更新 更多