参见:如何构建基本迭代器?
迭代是一个通用术语,指的是逐个处理某个东西中的每个项目。只要您使用循环(显式或隐式)遍历一组项目,就属于迭代。
在Python中,可迭代对象和迭代器有特定的含义。
可迭代对象是具有__iter__
方法的对象,该方法返回一个迭代器,或者定义了一个__getitem__
方法,该方法可以从零开始连续索引(并在索引不再有效时引发IndexError
)。 因此,可迭代对象是您可以从中获取迭代器的对象。
迭代器是具有next
(Python 2)或__next__
(Python 3)方法的对象。
每当您在Python中使用for
循环,map
或列表推导等功能时,都会自动调用next
方法来从迭代器获取每个项目,从而完成迭代的过程。
学习的好起点是教程中的迭代器部分和标准类型页面的迭代器类型部分。掌握基础知识后,可以尝试阅读函数式编程 HOWTO 中的 迭代器部分。
collections.abc.AsyncIterator
检查是否存在 __aiter__
和 __anext__
方法。这是 Python 3.6 中的新功能。 - Janus Troelsen__len__
必须与迭代相关联?知道某物的长度如何帮助您对其进行迭代? - shadowtalker__getitem__
一起使用。 - jlh{'a': 'hi', 'b': 'bye'}
的长度为2,但不能通过0、1或2进行索引。 - shadowtalker__iter__
方法。我认为jlh指的是特定可迭代对象,因为它们定义了:“一个__getitem__
方法,可以从零开始使用顺序索引”。 - Richfor x in iterable: ...
或者
- 任何您可以使用iter()
调用以返回迭代器的东西:iter(obj)
或者
- 定义了__iter__
方法以返回新迭代器的对象,或者它可能具有适用于索引查找的__getitem__
方法。__next__
方法,该方法:StopIteration
信号表示完成__iter__
方法,该方法返回self
)。__next__
方法的拼写方式为next
,而在Python 2中则不同。
- 内置函数next()
会调用传递给它的对象上的__next__
方法。>>> s = 'cat' # s is an ITERABLE
# s is a str object that is immutable
# s has no state
# s has a __getitem__() method
>>> t = iter(s) # t is an ITERATOR
# t has state (it starts by pointing at the "c"
# t has a next() method and an __iter__() method
>>> next(t) # the next() function returns the next value and advances the state
'c'
>>> next(t) # the next() function returns the next value and advances
'a'
>>> next(t) # the next() function returns the next value and advances
't'
>>> next(t) # next() raises StopIteration to signal that iteration is complete
Traceback (most recent call last):
...
StopIteration
>>> iter(t) is t # the iterator is self-iterable
for
循环,而第一个要点涉及“循环遍历”。请问您能否解决这些问题? - fountainheaditer()
”改为“anything you can pass to iter()
”,使句子更通俗易懂,但不改变原意。 - fountainhead__getitem__()
方法而没有__iter__()
方法,那么可迭代对象的一个例子是什么? - Niko Pasanenclass IterableExample(object):
def __iter__(self):
return self
def next(self):
pass
替代
class Iterator(object):
def next(self):
pass
class Iterable(object):
def __iter__(self):
return Iterator()
想象一下你能做什么:
class SmartIterableExample(object):
def create_iterator(self):
# An amazingly powerful yet simple way to create arbitrary
# iterator, utilizing object state (or not, if you are fan
# of functional), magic and nuclear waste--no kittens hurt.
pass # don't forget to add the next() method
def __iter__(self):
return self.create_iterator()
注释:
我再次重申:迭代器不可迭代。 迭代器不能作为for
循环中的“源”。for
循环主要需要的是__iter__()
(返回具有next()
的内容)。
当然,for
并不是唯一的迭代循环,因此上述规则也适用于其他结构(如while
…)。
迭代器的next()
可以抛出StopIteration以停止迭代。 但不必这样做,它可以永远迭代或使用其他方法。
在上述“思考过程”中,_i
实际上不存在。 我编了这个名字。
Python 3.x中有一个小变化:next()
方法(而不是内置方法)现在必须称为__next__()
。 是的,一直都应该是这样。
你也可以这样想:可迭代对象具有数据,迭代器提取下一个项
免责声明:我不是任何Python解释器的开发人员,因此我不真正知道解释器的“想法”。 上述思考仅是展示我如何从其他解释、实验和Python新手的实际经验中理解该主题。
for
循环需要一个迭代器(“看,一个for循环。看起来需要一个迭代器……赶紧拿一个。”)。但是在结尾的注释中你又说,“迭代器不能用作for
循环中的源”……? Translated: 很好,但我还是有点困惑。我原以为你的黄色框是在说for
循环需要一个迭代器(“看,一个for循环。看起来需要一个迭代器……赶紧拿一个。”)。但是在结尾的注释中你又说,“迭代器不能用作for
循环中的源”……? - Racing Tadpolepass
?我猜你的意思是要求有人实现获取下一个的方法,因为'next'必须返回一些东西。 - nealmcbpass
的用处) - Alois Mahdalpass
时,我认为它是为了语法而存在的。我刚刚在 省略号对象 上找到了一些有趣的答案:你可以使用 ...
来表示一个“稍后完成”的块。NotImplemented
也是可用的。 - nealmcbfor
循环中用作“源”。我理解你回答的重点并且除此之外也很喜欢它,但我认为修复这个问题会更好一些。 - Rich可迭代对象是一个具有__iter__()
方法的对象。它可以被多次迭代,例如list()
和tuple()
。
迭代器是迭代的对象。它由__iter__()
方法返回,通过自己的__iter__()
方法返回它本身,并具有一个next()
方法(在3.x中为__next__()
)。
迭代是调用next()
或__next__()
直到它引发StopIteration
的过程。
示例:
>>> a = [1, 2, 3] # iterable
>>> b1 = iter(a) # iterator 1
>>> b2 = iter(a) # iterator 2, independent of b1
>>> next(b1)
1
>>> next(b1)
2
>>> next(b2) # start over, as it is the first call to b2
1
>>> next(b1)
3
>>> next(b1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> b1 = iter(a) # new one, start over
>>> next(b1)
1
for i in [1,3,4,6]: print(i)
/ for i in {1,3,4,6}: print(i)
/ for i in (1,3,4,6): print(i)
。此外,查看文档或语言规范。 - glglgl这是我的备忘单:
sequence
+
|
v
def __getitem__(self, index: int):
+ ...
| raise IndexError
|
|
| def __iter__(self):
| + ...
| | return <iterator>
| |
| |
+--> or <-----+ def __next__(self):
+ | + ...
| | | raise StopIteration
v | |
iterable | |
+ | |
| | v
| +----> and +-------> iterator
| ^
v |
iter(<iterable>) +----------------------+
|
def generator(): |
+ yield 1 |
| generator_expression +-+
| |
+-> generator() +-> generator_iterator +-+
测验:
__iter__()
方法可以实现为生成器吗? __next__
方法的可迭代对象不一定是迭代器吗?答案:
__iter__
方法。拥有 __iter__
就足以成为可迭代对象。 因此,每个迭代器都是可迭代对象。调用 __iter__
时,它应该返回一个迭代器(在上面的图表中返回 <iterator>
)。调用生成器会返回一个生成器迭代器,这是一种迭代器类型。
__next__
方法的可迭代对象不一定是迭代器。要成为迭代器,还必须具有 __iter__
方法。class Iterable1:
def __iter__(self):
# a method (which is a function defined inside a class body)
# calling iter() converts iterable (tuple) to iterator
return iter((1,2,3))
class Iterable2:
def __iter__(self):
# a generator
for i in (1, 2, 3):
yield i
class Iterable3:
def __iter__(self):
# with PEP 380 syntax
yield from (1, 2, 3)
# passes
assert list(Iterable1()) == list(Iterable2()) == list(Iterable3()) == [1, 2, 3]
以下是一个示例:
class MyIterable:
def __init__(self):
self.n = 0
def __getitem__(self, index: int):
return (1, 2, 3)[index]
def __next__(self):
n = self.n = self.n + 1
if n > 3:
raise StopIteration
return n
# if you can iter it without raising a TypeError, then it's an iterable.
iter(MyIterable())
# but obviously `MyIterable()` is not an iterator since it does not have
# an `__iter__` method.
from collections.abc import Iterator
assert isinstance(MyIterable(), Iterator) # AssertionError
__iter__
方法而成为可迭代对象。您可以通过编辑此答案来详细解释第二个和第三个要点吗? - AnV__iter __()
返回一个迭代器。生成器是一种迭代器,因此可以用于这个目的。关于第三点:我只能猜测,但我认为如果缺少__iter __()
或者它没有返回self
,那么它就不是一个迭代器,因为迭代器的__iter __()
必须返回self
。 - glglglisinstance(MyIterable(), collections.abc.Iterable)
也是 False。@_@ - upgrd我不知道是否有帮助,但我总是喜欢在脑海中形象化概念以更好地理解它们。因此,由于我有一个小儿子,我用砖块和白纸来形象化可迭代/迭代器概念。
假设我们在黑暗的房间里,地上有砖块供我儿子玩耍。这些砖块大小、颜色各异,现在不重要。假设我们有5个这样的砖块。可以将这5个砖块描述为一个对象——比如说砖块套件。我们可以做很多事情——可以拿第一个然后拿第二个再拿第三个,可以改变砖块的位置,把第一个砖块放在第二个砖块上面等等。我们可以做许多种类的事情。因此,这个砖块套件是一个可迭代对象或序列,因为我们可以遍历每个砖块并对其进行操作。我们只能像我小儿子那样玩弄一个砖块一次。所以我再次想象这个砖块套件是一个可迭代对象。
现在记住我们在黑暗的房间里。或者几乎黑暗。问题是我们并看不清这些砖块,它们是什么颜色,什么形状等等。因此,即使我们想对它们进行操作——即遍历它们——我们也不知道该怎么做,因为太黑了。
我们可以在第一个砖块旁边——作为砖块套件的元素——放一张白色荧光纸,以便我们看到第一个砖块元素的位置。每次取出砖块时,我们将白色荧光纸替换为下一个砖块,以便在黑暗房间中能够看到它。这张白纸不过是一个迭代器。它也是一个对象。但是,它是一个我们可以使用并玩弄可迭代对象——砖块套件——元素的对象。
顺便说一下,这解释了我的早期错误,当我在IDLE中尝试以下操作时会收到TypeError:
>>> X = [1,2,3,4,5]
>>> next(X)
Traceback (most recent call last):
File "<pyshell#19>", line 1, in <module>
next(X)
TypeError: 'list' object is not an iterator
这里的List X 是我们的积木套件,而不是一张白纸。我需要先找到一个迭代器:
>>> X = [1,2,3,4,5]
>>> bricks_kit = [1,2,3,4,5]
>>> white_piece_of_paper = iter(bricks_kit)
>>> next(white_piece_of_paper)
1
>>> next(white_piece_of_paper)
2
>>>
不知道这是否有帮助,但它对我有帮助。如果有人可以确认/纠正概念的可视化,我将不胜感激。这将帮助我学到更多。
可迭代对象具有
__iter__
方法,每次实例化一个新的迭代器。迭代器实现了
__next__
方法,返回单个项,并实现了__iter__
方法,返回self
。因此,迭代器也是可迭代的,但可迭代对象不是迭代器。
卢西亚诺·拉玛略,《流畅的Python》。
可迭代对象:可以被迭代的东西是可迭代的,例如像列表、字符串等序列。此外,它具有__getitem__
方法或__iter__
方法。现在,如果我们在该对象上使用iter()
函数,我们将获得一个迭代器。
迭代器:当我们从iter()
函数获取迭代器对象时,我们调用__next__()
方法(在Python3中)或简单地使用next()
(在Python2中)逐个获取元素。这个类或这个类的实例被称为迭代器。
来自文档:
迭代器在Python中无处不在且统一。在幕后,for语句在容器对象上调用iter()
。该函数返回一个迭代器对象,该对象定义了方法__next__()
,该方法逐个访问容器中的元素。当没有更多元素时,__next__()
会引发一个StopIteration异常,告诉for循环终止。您可以使用内置函数next()
调用__next__()
方法;以下示例显示了所有内容的工作原理:
>>> s = 'abc'
>>> it = iter(s)
>>> it
<iterator object at 0x00A1DB50>
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
next(it)
StopIteration
一个类的例子:
class Reverse:
"""Iterator for looping over a sequence backwards."""
def __init__(self, data):
self.data = data
self.index = len(data)
def __iter__(self):
return self
def __next__(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
>>> rev = Reverse('spam')
>>> iter(rev)
<__main__.Reverse object at 0x00A1DB50>
>>> for char in rev:
... print(char)
...
m
a
p
s
迭代器是实现 iter 和 next 方法的对象。如果这些方法被定义,我们可以使用 for 循环或理解。
class Squares:
def __init__(self, length):
self.length = length
self.i = 0
def __iter__(self):
print('calling __iter__') # this will be called first and only once
return self
def __next__(self):
print('calling __next__') # this will be called for each iteration
if self.i >= self.length:
raise StopIteration
else:
result = self.i ** 2
self.i += 1
return result
迭代器会被用尽,这意味着在你遍历完所有项目后,就不能再次遍历了,必须重新创建一个新的对象。假设你有一个类,它保存了城市的属性,并且你想要进行迭代遍历。
class Cities:
def __init__(self):
self._cities = ['Brooklyn', 'Manhattan', 'Prag', 'Madrid', 'London']
self._index = 0
def __iter__(self):
return self
def __next__(self):
if self._index >= len(self._cities):
raise StopIteration
else:
item = self._cities[self._index]
self._index += 1
return item
类Cities的实例是一个迭代器。如果您想要重新迭代城市,则必须创建一个新对象,这是一项昂贵的操作。可以将该类分为两个类:一个返回城市,另一个返回迭代器,该迭代器使用城市作为init参数。
class Cities:
def __init__(self):
self._cities = ['New York', 'Newark', 'Istanbul', 'London']
def __len__(self):
return len(self._cities)
class CityIterator:
def __init__(self, city_obj):
# cities is an instance of Cities
self._city_obj = city_obj
self._index = 0
def __iter__(self):
return self
def __next__(self):
if self._index >= len(self._city_obj):
raise StopIteration
else:
item = self._city_obj._cities[self._index]
self._index += 1
return item
__iter__()
方法,返回一个新的迭代器对象实例即可。class Cities:
def __init__(self):
self._cities = ['New York', 'Newark', 'Istanbul', 'Paris']
def __len__(self):
return len(self._cities)
def __iter__(self):
return self.CityIterator(self)
class CityIterator:
def __init__(self, city_obj):
self._city_obj = city_obj
self._index = 0
def __iter__(self):
return self
def __next__(self):
if self._index >= len(self._city_obj):
raise StopIteration
else:
item = self._city_obj._cities[self._index]
self._index += 1
return item
迭代器有__iter__
和__next__
,可迭代对象只有__iter__
,因此我们可以说迭代器也是可迭代对象,但它们是会用尽的可迭代对象。另一方面,可迭代对象永远不会用尽,因为它们总是返回一个新的迭代器来进行迭代。
您会注意到,可迭代对象的主要部分在于迭代器中,而可迭代对象本身只是一个额外的层次结构,使我们能够创建和访问迭代器。
Python有一个内置函数iter(),它调用__iter__()
。当我们遍历可迭代对象时,Python调用iter(),它返回一个迭代器,然后开始使用迭代器的__next__()
来遍历数据。
请注意,在上面的示例中,Cities创建了一个可迭代对象,但它不是序列类型,这意味着我们无法通过索引获取城市。要解决这个问题,我们应该只需将__get_item__
添加到Cities类中即可。
class Cities:
def __init__(self):
self._cities = ['New York', 'Newark', 'Budapest', 'Newcastle']
def __len__(self):
return len(self._cities)
def __getitem__(self, s): # now a sequence type
return self._cities[s]
def __iter__(self):
return self.CityIterator(self)
class CityIterator:
def __init__(self, city_obj):
self._city_obj = city_obj
self._index = 0
def __iter__(self):
return self
def __next__(self):
if self._index >= len(self._city_obj):
raise StopIteration
else:
item = self._city_obj._cities[self._index]
self._index += 1
return item