关于Python __iter__ 和 next() 输出的解释

2 投票
2 回答
1100 浏览
提问于 2025-04-18 15:54

我从Python 2.7.8的官方文档中学到了如何使用迭代器和生成器。现在我有一个和好奇心有关的问题。

it = iter("abcde")
print it
>>> <iterator object at 0x7ff4c2b3bad0>

class example1():
    def __init__(self, word):
        self.word = word
        self.index = len(word)
    def __iter__(self):
        for x in range(self.index - 1, -1, -1):
            yield self.word[x]

a = example1("altalena")
print iter(a)
>>> <generator object __iter__ at 0x7f24712000a0>

在上面的例子中,当我打印迭代器时,我看到的是“生成器”、“迭代器”对象和十六进制的ID。为什么我在下面的代码中不能做到这一点呢?

class example2():
    def __init__(self, word):
        self.word = word
        self.index = len(word)
    def __iter__(self):
        return self
    def next (self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.word[self.index]
a = example2()
print iter(a)
>>> <__main__.example2 instance at 0x7f89ee2de440>

我觉得这可能是因为iter中的“return self”,这导致了类的实例,但我不知道怎么做才能得到更正确的输出。这可能没什么用,但我不知道为什么会这样,也不知道怎么避免。

2 个回答

0

我觉得你并没有遇到问题,只是对这里发生的事情不太明白。

一般来说,iter(object) 会返回一个迭代器,这个迭代器是用来遍历这个可迭代对象的。

这个迭代器可以通过调用 __iter__() 方法获得,或者如果这个方法不存在,就会用一个包装对象来调用 __getitem__() 方法,直到遍历完所有元素(这时会抛出 IndexError 错误)。

通过 __iter__() 返回的对象可以是可迭代对象本身(就像你第二个例子那样),也可以是其他东西。特别地,如果你把 __iter__() 定义成一个生成器函数,就会返回一个生成器对象,这在你第一个例子中就是这样。

实际的遍历是通过迭代器对象和它的 next() 或者 __next__() 方法来进行的。

0

生成器是一种特殊的迭代器。你的 example1 类返回了一个生成器,因为在 __iter__ 方法中使用了 yield;这意味着它返回了一个 独立的迭代器对象。所以,example1 类是 可迭代的,但它本身不是一个迭代器。

在你的第二个例子中,类的 __iter__ 方法返回了 self。这不仅仅是可迭代的,它本身就是一个 迭代器。因为它返回的是 self,所以 这里没有独立的对象

Python 明确区分了 可迭代对象迭代器。一个 可迭代对象可以 潜在地 被迭代。而 迭代器 则是实际进行迭代的对象。通过使用 iter(),你是在请求 Python 为给定的 可迭代对象 生成一个 迭代器

这就是为什么 iter(stringobject) 返回一个新对象;你从 可迭代的 字符串中生成了一个 迭代器

你需要理解这个区别,因为迭代的过程需要一个能够保持状态的东西;也就是说,我们现在处于哪个阶段。而 迭代器 就是用来跟踪这个状态的对象,这样每次你在迭代器上调用 .next() 方法时,就能得到下一个值,如果没有下一个值了,就会抛出 StopIteration

所以在你的例子中,字符串和 example1 都只是 可迭代的,调用 iter() 会产生一个新的独立 迭代器

然而,你的 example2 是它自己的 迭代器。对它调用 iter() 不会产生一个独立的对象。你不能从一个已经是 迭代器 的东西中创建独立的 迭代器

如果你想为你的 example2 类生成一个新的独立 迭代器,你需要在 __iter__ 中返回一个不同的、独立的对象:

class ExampleIterator(object):
    def __init__(self, source):
        self.source = source
        self.position = len(source)

    def __iter__(self):
        return self

    def next(self):
        if self.position <= 0:
            raise StopIteration
        self.position -= 1
        return self.source[self.position]

class Example2():
    def __init__(self, word):
        self.word = word

    def __iter__(self):
        return ExampleIterator(self)

在这里,Example2 又只是一个 可迭代的,而不是一个 迭代器__iter__ 方法返回一个新的、独特的 ExampleIterator() 实例,它负责跟踪迭代的状态。

撰写回答