Python循环在自定义容器上不起作用

2 投票
5 回答
837 浏览
提问于 2025-04-16 08:35

编辑: 我在我的 Map 类中添加了 __iter__ 方法(我忘了它没有继承自 Tree),但现在在使用 for 循环时返回的是“生成器对象”。

<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'

所以我的 next 函数有问题,对吧?


为了好玩,我在 Python 中创建了一个红黑树,它运行得很好。现在为了模仿 C++ 的 STL,我正在创建一个 Map 类来包装这个树,作为 Python 字典的替代品。

问题是当我尝试遍历这个 Map 时,它没有正常工作。

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……

Map 的定义是:

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))

根据我的理解,我需要为我的树创建一个迭代器,这样才能正常工作。我不太确定该怎么做,于是我四处查找并结合了几种方法: (在我的红黑树实现中,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

当然可以!请看下面的内容:

在编程中,有时候我们需要让程序做一些事情,比如计算、显示信息或者处理数据。为了实现这些功能,我们会用到一些代码块。代码块就像是一个个小工具,帮助我们完成特定的任务。

例如,当我们想要计算两个数字的和时,我们可以写一段代码来实现这个功能。这个代码块会告诉计算机:“嘿,帮我把这两个数字加起来!”

有些时候,代码块可能会包含一些条件,比如“如果这个数字大于10,就做某件事;否则,做另一件事。”这样可以让程序根据不同的情况做出不同的反应。

总之,代码块是编程的基本组成部分,它们帮助我们把想法变成实际的操作。希望这个解释能让你对代码块有个更清晰的理解!

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 _
1

我认为,要在条件语句中把 map 当作一个迭代器使用,Map 类必须实现 next 和 iter 方法。我这样理解对吗?

简单来说,你需要在 Map 类里添加一个 __iter__() 方法和一个 next() 方法。

3

你的 Map 类没有 __iter__ 这个方法,所以在用 for 循环的时候,它会调用 __getitem__ 方法来代替。你应该让 Map 类继承自 SearchTree,或者在 Map 类里面实现 __iter__ 方法。

撰写回答