container.__iter__()和iterator.__iter__()有什么区别?

3 投票
3 回答
1364 浏览
提问于 2025-04-17 06:18

我对Python不太熟,所以请不要打击我。

>>> a = ['a', 'b', 'c']
>>> a.__iter__()
<listiterator object at 0x03531750>
>>> a.__iter__().__iter__()
<listiterator object at 0x03531690>

我发现这两个列表迭代器对象在不同的地方(确实,0x03531750看起来像是一个地址?)。我想知道这两个对象是不是一样的,只是住在不同的地方,还是说它们是不同的对象?

3 个回答

1

0x03531690 是这个对象在虚拟内存中的位置,简单来说,这个信息对你没有什么实际意义。

比如:

>>> a = ['a', 'b', 'c']
>>> a.__iter__()
<listiterator object at 0x102d70d90>
>>> a.__iter__()
<listiterator object at 0x102d70e10>

我不太明白你想干嘛,把一个列表的迭代器加到另一个迭代器上,这样做是为了遍历一个字符列表吗? :)

2

iter(iterable) 会返回一个迭代器,这样你就可以通过调用 next(iterator) 来获取 iterable 中的下一个项目,或者在没有更多项目时会收到 StopIteration 的异常提示。

iter(iterator) 应该返回它自己:

>>> it = iter([])
>>> it is iter(it)
True

不用担心内存位置的问题,比如 jython 和 pypy 可能会返回不同的东西。

10

一个迭代器有一个叫做 __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

撰写回答