首先,我必须说我在阅读之前阅读了很多SO帖子,因为我找不到我想要的内容,或者我可能没有理解。 所以这就是
我有点理解Iterables和Iterators是什么。因此任何包含项目的Lists / Tuples / Sets之类的容器对象都可以迭代,称为Iterables。现在迭代Iterables你需要迭代器及其发生的方式是因为__iter__
方法为你提供了类型的Iterator对象,然后调用Iterator对象上的__next__
来提取值。
因此,要使任何对象可迭代,您需要定义 iter 和 next 方法,我认为对于列表也是如此。但是最近我发现了这个奇怪的部分。
l1 = [1,2,3]
hasattr(l1, "__next__")
Out[42]: False
g = (x for x in range(3))
hasattr(g, "__next__")
Out[44]: True
现在因为这些列表支持Iterator协议,为什么实现中缺少__next__
方法,如果它确实缺失,那么列表的迭代如何工作?
list_iterator = iter(l1)
next(list_iterator)
Out[46]: 1
next(list_iterator)
Out[47]: 2
next(list_iterator)
Out[48]: 3
next(list_iterator)
Traceback (most recent call last):
File "C:\Users\RJ\Anaconda3\lib\site-packages\IPython\core\interactiveshell.py", line 2910, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-49-56e733bbb896>", line 1, in <module>
next(list_iterator)
StopIteration
gen0_iterator = iter(g)
gen_iterator = iter(g)
next(gen_iterator)
Out[57]: 0
next(gen_iterator)
Out[58]: 1
next(gen_iterator)
Out[59]: 2
next(gen_iterator)
Traceback (most recent call last):
File "C:\Users\RJ\Anaconda3\lib\site-packages\IPython\core\interactiveshell.py", line 2910, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-60-83622dd5d1b9>", line 1, in <module>
next(gen_iterator)
StopIteration
gen_iterator1 = iter(g)
next(gen_iterator1)
Traceback (most recent call last):
File "C:\Users\RJ\Anaconda3\lib\site-packages\IPython\core\interactiveshell.py", line 2910, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-62-86f9b3cc341f>", line 1, in <module>
next(gen_iterator1)
StopIteration
我为列表创建了一个迭代器,然后在其上调用next方法来获取元素并且它可以工作。
现在,如果前一个hasattr(a, "__next__")
返回False
,那么我们如何能够在迭代器对象上调用下一个方法来获取列表。
现在最初的问题让我想到这一切,无论我多少次遍历列表,它都不会耗尽并且调用iter()
每次都会返回一个新的迭代器对象,但是在生成器的情况下,这不会发生,并且一旦生成器耗尽,无论您调用iter()
多少次,它总会返回已经引发StopIteration
异常的同一对象这是真的,因为迭代器曾经提出StopIteration
,它总是会,但为什么它不会发生在列表中。
此外,这与python文档对conatiner.__ iter__所说的同步,container.__iter__
为您提供了类型的迭代器对象,iterator.__ iter__和iterator.__iter__
为您提供了迭代器对象本身,这正是调用生成器iter()
一次又一次地返回相同对象的原因。但为什么,更重要的是如何?
这里要注意的另一件事是
isinstance(l1 , collections.Iterator)
Out[65]: False
isinstance(g , collections.Iterator)
Out[66]: True
所以这表明b / w Iterables和Iterators有一些实现差异,但是我找不到任何这样的细节,因为它们都实现了__iter__
和__next__
方法,所以从这里开始行为的变化来了。因此,对于iterables,__iter__
返回的内容与__iter__
的iterables(生成器)返回的内容不同。如果有人可以用I __iter__
的一些例子来解释Iterables和Iterataors,那将会非常有用。最后有一些关于yield
的谜题,因为这是使普通函数成为生成器的神奇词(所以是一种迭代器),所以`yield的__iter__
和__next__
看起来像
我已尽力解释这个问题,但如果还有什么遗漏,请告诉我,我会尽力澄清我的问题。
答案 0 :(得分:0)
它有点不同。 iterables 有一个返回迭代器的__iter__
方法。 迭代器采用__next__
方法(并且通常也有__iter__
方法,以便iter()
对它们起作用 - 但这不是必需的。)
列表是可迭代的:
>>> l = [1,2,3]
>>> hasattr(l, "__iter__")
True
>>> hasattr(l, "__next__")
False
>>> l_iter = iter(l)
>>> hasattr(l_iter, "__next__")
True
>>> hasattr(l_iter, "__iter__")
True
>>> l_iter == iter(l_iter)
True
每次使用时都会给你新的迭代器
>>> list(l)
[1, 2, 3]
>>> list(l)
[1, 2, 3]
>>> l_iter = iter(l)
>>> list(l_iter)
[1, 2, 3]
>>> list(l_iter)
[]
each time you use them
>>> list(l)
[1, 2, 3]
>>> list(l)
[1, 2, 3]
>>> iter(l) == iter(l)
False
但是列表迭代器本身就是一次性
>>> l_iter = iter(l)
>>> list(l_iter)
[1, 2, 3]
>>> list(l_iter)
[]
生成器是一个迭代器,不是可迭代的,也是一次性的。
>>> g = (x for x in range(3))
>>> hasattr(g, "__iter__")
True
>>> hasattr(g, "__next__")
True
>>> g == iter(g)
True
>>>
>>> list(g)
[0, 1, 2]
>>> list(g)
[]