gpt4 book ai didi

python - 为什么在 Python 中有一个 __iter__ 方法?

转载 作者:太空宇宙 更新时间:2023-11-03 13:38:02 25 4
gpt4 key购买 nike

为什么要有一个 __iter__ 方法?如果一个对象是一个迭代器,那么拥有一个返回自身的方法是没有意义的。如果它不是迭代器而是可迭代的,即带有 __iter____getitem__ 方法的东西,那么为什么要定义返回迭代器但不是迭代器本身?在 Python 中,什么时候会想要定义一个本身不是迭代器的可迭代对象?或者,什么是可迭代但不是迭代器的示例?

最佳答案

尝试一次回答一个问题:

Why have an __iter__ method? If an object is an iterator, then it is pointless to have a method which returns itself.

这不是没有意义的。迭代器协议(protocol)需要 __iter____next__(或 Python 2 中的 next)方法。我见过的所有理智的迭代器都只是在它们的 __iter__ 方法中 return self ,但拥有该方法仍然至关重要。没有它会导致各种怪异,例如:

somelist = [1, 2, 3]
it = iter(somelist)

现在

iter(it)

for x in it: pass

会抛出一个 TypeError 并提示 it 不可迭代,因为当 iter(x) 被调用时(这隐含地发生在你使用一个 for 循环)它期望参数对象 x 能够产生一个迭代器(它只是试图在该对象上调用 __iter__) .具体示例(Python 3):

>>> class A:
... def __iter__(self):
... return B()
...
>>> class B:
... def __next__(self):
... pass
...
>>> iter(iter(A()))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'B' object is not iterable

考虑任何函数,特别是来自 itertools 的函数期望一个可迭代的,例如 dropwhile .使用任何具有 __iter__ 方法的对象调用它都可以,无论它是不是迭代器的可迭代对象还是迭代器 - 因为调用 iter 时您可以期待相同的结果 以该对象作为参数。在这里对两种可迭代对象进行奇怪的区分会违背 python 强烈支持的鸭子类型原则。

像这样的巧妙技巧

>>> a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> list(zip(*[iter(a)]*3))
[(1, 2, 3), (4, 5, 6), (7, 8, 9)]

如果您不能将迭代器传递给 zip,就会停止工作。

why would one want to ever define something which returns an iterator but is not an iterator itself

让我们考虑一下这个简单的列表迭代器:

>>> class MyList(list):
... def __iter__(self):
... return MyListIterator(self)
>>>
>>> class MyListIterator:
... def __init__(self, lst):
... self._lst = lst
... self.index = 0
... def __iter__(self):
... return self
... def __next__(self):
... try:
... n = self._lst[self.index]
... self.index += 1
... return n
... except IndexError:
... raise StopIteration
>>>
>>> a = MyList([1,2,3])
>>> for x in a:
... for x in a:
... x
...
1
2
3
1
2
3
1
2
3

请记住,对于两个 for 循环,iter 都是通过相关的可迭代对象调用的,每次从对象的 中期望一个 迭代器>__iter__ 方法。

现在,如果每次使用 for 循环时都不会生成迭代器,当 MyList 时,您如何能够跟踪任何迭代的当前状态对象同时迭代任意次数?哦,是的,你不能。 :)

编辑:奖金和对 Tadhg McDonald-Jensen 评论的回复

可重用迭代器并非不可想象,但当然有点奇怪,因为它依赖于使用“非消耗性”迭代器(即不是经典迭代器)进行初始化:

>>> class riter(object):
... def __init__(self, iterable):
... self.iterable = iterable
... self.it = iter(iterable)
... def __next__(self): # python 2: next
... try:
... return next(self.it)
... except StopIteration:
... self.it = iter(self.iterable)
... raise
... def __iter__(self):
... return self
...
>>>
>>> a = [1, 2, 3]
>>> it = riter(a)
>>> for x in it:
... x
...
1
2
3
>>> for x in it:
... x
...
1
2
3

关于python - 为什么在 Python 中有一个 __iter__ 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36681312/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com