关于Python __iter__ 和 next() 输出的解释
我从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 个回答
我觉得你并没有遇到问题,只是对这里发生的事情不太明白。
一般来说,iter(object)
会返回一个迭代器,这个迭代器是用来遍历这个可迭代对象的。
这个迭代器可以通过调用 __iter__()
方法获得,或者如果这个方法不存在,就会用一个包装对象来调用 __getitem__()
方法,直到遍历完所有元素(这时会抛出 IndexError
错误)。
通过 __iter__()
返回的对象可以是可迭代对象本身(就像你第二个例子那样),也可以是其他东西。特别地,如果你把 __iter__()
定义成一个生成器函数,就会返回一个生成器对象,这在你第一个例子中就是这样。
实际的遍历是通过迭代器对象和它的 next()
或者 __next__()
方法来进行的。
生成器是一种特殊的迭代器。你的 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()
实例,它负责跟踪迭代的状态。