Python for循环不适用于自定义容器

时间:2010-12-15 15:52:54

标签: python

编辑:我将__iter__添加到我的Map类中(我忘了它没有从Tree继承),但现在for循环返回“generator objects”:

<generator object _next at 0x82a4b94>
Traceback (most recent call last):
  File "Map.py", line 43, in <module>
    print "First: %s, Second: %s" % (pair.first(), pair.second())
AttributeError: 'generator' object has no attribute 'first'

所以我的下一个功能出现了问题,对吗?


为了好玩,我用Python创建了一个RedBlack树,它运行正常。现在从C ++复制STL我正在创建一个Map类来包装树,以替代Python dict。

问题是当我尝试循环浏览地图时,它无法正常工作。

phonebook = Map()
phonebook["Joe"] = "555-555-3422"
phonebook["Rob"] = "231-523-2357"

for pair in phonebook:
    print "First: %s, Second: %s" % (pair.first(), pair.second())

我得到的错误是:

Traceback (most recent call last):
  File "Map.py", line 38, in <module>
    for pair in phonebook:
  File "Map.py", line 19, in __getitem__
    return self._tree.find(key)
  File "Python/Tree/SearchTree.py", line 82, in find
    raise TreeException('No node with key %s' % key)
Tree.TreeException: 'No node with key 0'

我不知道为什么它正在寻找键0,当我的键是字符串时。 使用pdb我注意到在for循环开始后,执行的第一行是调用__getitem__,键为0 ....

地图定义为:

class Map:
    def __init__(self):
        self._tree = RedBlackTree()

    def __getitem__(self, key):
        return self._tree.find(key)

    def __setitem__(self, key, item):
        self._tree.insert(Pair(key, item))

根据我的理解,我必须为我的树创建一个迭代器,以使其正常工作。我不太清楚如何做到这一点,所以我环顾四周并结合了几种方法: (在我的RedBlack树实现中,NULL是一个实际节点)

class TreeIterator():
    def __init__(self, root, size):
        self._current = root
        self._size = size
        self.num_visited = 0

    def __iter__(self):
        return self

    def next(self):
        return self._next(self._current)

    def _next(self, curr):
        self.num_visited = self.num_visited + 1
        if self.num_visited == self._size:
            raise StopIteration

        if curr.left is not None and curr.left is not TreeNode.NULL:
            for node in _next(curr.left):
                yield node

        yield curr
        if curr.right is not None and curr.right is not TreeNode.NULL:
            for node in _next(curr.right):
                yield node

并在我的SearchTree超类中:

def __iter__(self):
    return TreeIterator(self.root, self.size)

我做错了什么?

5 个答案:

答案 0 :(得分:3)

您的Map类没有__iter__方法,因此for会调用__getitem__。您应该从SearchTree继承Map或在Map中实现__iter__

答案 1 :(得分:1)

我认为为了在条件中使用map作为迭代器,Map类必须实现next和iter。我错了吗?

基本上你要在Map类中添加__iter__()和next()方法。

答案 2 :(得分:0)

如果你想让一个对象可迭代,以便你可以用for循环遍历它,你必须实现__iter__()next()(解释here )。

当你循环遍历具有这两种方法的对象时,Python首先在对象上调用__iter__()。此方法返回具有next()方法的对象。然后,Python一遍又一遍地调用next(),逐个获取对象中的项目,直到next()引发StopIteration错误。

有两种简单的方法可以使您的代码正常工作。第一种方法是在地图上实现__iter__()next()方法,这些方法调用self._tree上的等价物,第二种方法是让你的地图继承自树类,然后你得到迭代,没有额外的工作。

答案 3 :(得分:0)

class xxx (object) :
    def __init__ (self) :
        self._values = [1, 2, 3]

    def __iter__ (self) :
        return self._next ()

    def _next (self) :
       for v in self._values :
            yield v

       raise StopIteration

x = xxx ()
for _ in x : print _

答案 4 :(得分:0)

next()应该是常规函数,而不是生成器。 return来自yield,不要{{1}}。