container.__iter__()和iterator.__iter__()有什么区别?
我对Python不太熟,所以请不要打击我。
>>> a = ['a', 'b', 'c']
>>> a.__iter__()
<listiterator object at 0x03531750>
>>> a.__iter__().__iter__()
<listiterator object at 0x03531690>
我发现这两个列表迭代器对象在不同的地方(确实,0x03531750
看起来像是一个地址?)。我想知道这两个对象是不是一样的,只是住在不同的地方,还是说它们是不同的对象?
3 个回答
0x03531690 是这个对象在虚拟内存中的位置,简单来说,这个信息对你没有什么实际意义。
比如:
>>> a = ['a', 'b', 'c']
>>> a.__iter__()
<listiterator object at 0x102d70d90>
>>> a.__iter__()
<listiterator object at 0x102d70e10>
我不太明白你想干嘛,把一个列表的迭代器加到另一个迭代器上,这样做是为了遍历一个字符列表吗? :)
iter(iterable)
会返回一个迭代器,这样你就可以通过调用 next(iterator)
来获取 iterable
中的下一个项目,或者在没有更多项目时会收到 StopIteration
的异常提示。
iter(iterator)
应该返回它自己:
>>> it = iter([])
>>> it is iter(it)
True
不用担心内存位置的问题,比如 jython 和 pypy 可能会返回不同的东西。
一个迭代器有一个叫做 __iter__()
的方法,这样你就可以用 iter()
来获取它的迭代器,尽管它本身已经是一个迭代器了。这让你在写使用迭代器的代码时,不用一直检查某个东西是不是已经是迭代器,方便多了。
所以你是先为列表获取一个迭代器,然后又为那个迭代器获取一个迭代器。一个迭代器的迭代器就是原来的那个迭代器(Python 不会再创建一个新的迭代器,因为没必要)。
到这里为止都很好。
迭代器是对象,和所有对象一样,它们有自己的生命周期。它们在你调用 __iter__()
(或者 iter()
)的时候被创建,当没有任何地方再引用它们时就会被销毁。在你的例子中,你调用了 a.__iter__()
,这就创建了一个列表迭代器。然后,因为你没有在其他地方保存这个迭代器的引用,所以这个迭代器几乎马上就被销毁了(虽然这是实现的细节)。所以你接下来的命令 a.__iter__().__iter__()
会为列表创建一个新的迭代器(只有一个,因为迭代器的迭代器是同一个迭代器)——它不会重用你在之前命令中创建的那个迭代器,因为那个迭代器已经不存在了。这就是为什么这些对象有不同的 ID;它们实际上是不同的对象。
如果你保存了第一个迭代器的引用,你会发现 a.__iter__()
和 a.__iter__().__iter__()
是同一个对象。试试这个:
a = ['a', 'b', 'c']
i = iter(a) # a.__iter__()
j = iter(i) # i.__iter__() which is a.__iter__().__iter__()
print i is j # True, they're the same object