问题:迭代器,可迭代和迭代到底是什么?
Python中“可迭代”,“迭代器”和“迭代”的最基本定义是什么?
我已经阅读了多个定义,但是我无法确定确切的含义,因为它仍然不会陷入。
有人可以在外行方面为我提供3个定义的帮助吗?
回答 0
迭代是一个总称,表示一件一件一件一件一件接一件的物品。每当您使用循环(显式或隐式)遍历一组项目时,即迭代。
在Python中,iterable和iterator具有特定的含义。
一个迭代是具有对象__iter__
返回一个方法迭代,或者其限定__getitem__
,可以采取顺序索引从零启动方法(并发出IndexError
时,索引不再有效)。因此,可迭代对象是可以从中获取迭代器的对象。
一个迭代器是具有一个对象next
(Python的2)或__next__
(Python 3的)方法。
每当在Python中使用for
循环或map
或列表理解等时,next
都会自动调用该方法以从迭代器获取每个项,从而进行迭代过程。
一个开始学习的好地方是本教程的迭代器部分和标准类型页面的迭代器类型部分。了解基础知识之后,请尝试“功能编程HOWTO”的“ 迭代器”部分。
回答 1
这是我在教授Python类时使用的解释:
一个ITERABLE是:
- 任何可以循环播放的内容(例如,您可以循环播放字符串或文件)或
- 任何可能出现在for循环右侧的内容:
for x in iterable: ...
或 - 您可以呼叫的任何内容
iter()
都会传回ITERATOR:iter(obj)
或 - 一个定义的对象,该对象
__iter__
返回一个新鲜的ITERATOR,或者它可能具有__getitem__
适合于索引查找的方法。
ITERATOR是一个对象:
- 状态会记住迭代过程中的位置,
- 使用以下
__next__
方法:- 返回迭代中的下一个值
- 更新状态以指向下一个值
- 通过提高发出信号
StopIteration
- 并且这是可自我迭代的(意味着它具有
__iter__
返回的方法self
)。
笔记:
__next__
Python 3中的方法是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
回答 2
上面的答案很棒,但是正如我所见到的大多数一样,对于像我这样的人来说,不要强调这种区别。
同样,人们倾向于通过在__foo__()
前面放置诸如“ X是具有方法的对象”之类的定义来获得“ Python风格” 。这样的定义是正确的-它们基于鸭子式的哲学,但是当试图以简单的方式理解概念时,对方法的关注往往会介于两者之间。
因此,我添加了我的版本。
用自然语言
- 迭代是在一行元素中一次获取一个元素的过程。
在Python中,
Iterable是一个很好的可迭代对象,简单地说,意味着可以在迭代中使用它,例如使用
for
循环。怎么样?通过使用迭代器。我会在下面解释。…,而迭代器是一个对象,它定义了如何实际执行迭代-特别是下一个元素是什么。这就是为什么它必须有
next()
方法的原因 。
迭代器本身也是可迭代的,区别在于它们的__iter__()
方法返回相同的object(self
),而不管其先前的调用是否已消耗其项目next()
。
那么,Python解释器看到for x in obj:
语句时会怎么想?
看,
for
循环。看起来像是一个迭代器的工作…让我们得到一个。…有obj
一个人,让我们问他。“先生
obj
,您有迭代器吗?” (…调用iter(obj)
,这些调用obj.__iter__()
愉快地发出了一个闪亮的新迭代器_i
。)好的,那很简单…让我们开始迭代。(
x = _i.next()
…x = _i.next()
…)
由于Mr. Mr obj
成功地通过了某种测试(通过某种方法返回有效的迭代器),因此我们用形容词来奖励他:您现在可以称他为“ Iterable Mr. obj
”。
但是,在简单的情况下,通常不会从分别拥有Iterator和Iterable中受益。因此,您仅定义一个对象,这也是它自己的迭代器。(Python并不真正在乎_i
发出的obj
不是那么闪亮,而仅仅是obj
它本身。)
这就是为什么在我见过的大多数示例中(以及一遍又一遍使我困惑的原因)中,您可以看到:
class 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()
但是,在某些情况下,可以从使迭代器与可迭代的对象分离中受益,例如,当您希望有一行项目,但需要更多的“游标”时。例如,当您要使用“当前”和“即将到来”的元素时,可以为这两个元素使用单独的迭代器。或从庞大列表中提取多个线程:每个线程都可以具有自己的迭代器以遍历所有项目。见@雷蒙德和@ glglgl的上述回答。
想象一下您可以做什么:
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新手的实际经验中展示了我如何理解该主题。
回答 3
可迭代对象是具有__iter__()
方法的对象。它可能会迭代多次,例如list()
s和tuple()
s。
迭代器是要迭代的对象。它由__iter__()
方法返回,通过自己的__iter__()
方法返回自身,并具有next()
方法(__next__()
在3.x中)。
迭代是调用此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
回答 4
这是我的备忘单:
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__
被调用时,它应该返回一个迭代器(return <iterator>
在上图中)。调用生成器将返回生成器迭代器,它是迭代器的一种。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
回答 5
我不知道它是否对任何人都有帮助,但我一直喜欢在脑海中形象化概念以更好地理解它们。因此,当我有一个小儿子时,我用砖块和白皮书形象化了迭代/迭代器的概念。
假设我们在黑暗的房间里,在地板上,我的儿子有砖头。现在,大小,颜色不同的砖都不再重要了。假设我们有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
清单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
>>>
不知道是否有帮助,但是对我有帮助。如果有人可以确认/纠正该概念的可视化,我将不胜感激。这将帮助我了解更多信息。
回答 6
可迭代: -这是迭代的迭代; 例如列表,字符串等序列。它也具有__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
回答 7
我认为您不会比文档简单得多,但是我会尝试:
- 可迭代的东西,可以被重复过。在实践中,它通常表示一个序列,例如具有开始和结束的某种事物,以及某种贯穿其中所有项目的方式。
您可以将Iterator视为辅助伪方法(或伪属性),该伪方法可提供(或保留)iterable中的下一个(或第一个)项。(实际上,它只是一个定义方法的对象
next()
)Merriam-Webster 对该词的定义可能最好地解释了迭代:
b:将计算机指令序列重复指定的次数或直到满足条件为止-比较递归
回答 8
iterable = [1, 2]
iterator = iter(iterable)
print(iterator.__next__())
print(iterator.__next__())
所以,
iterable
是可以循环的对象。例如list,string,tuple等。iter
在iterable
对象上使用该函数将返回迭代器对象。现在,此迭代器对象具有名为
__next__
(在Python 3中,或仅next
在Python 2中)的方法,您可以通过该方法访问iterable的每个元素。
因此,以上代码的输出将是:
1个
2
回答 9
可
__iter__
迭代对象具有每次都实例化新迭代器的方法。迭代器实现一个
__next__
返回单个项目的__iter__
方法和一个返回的方法self
。因此,迭代器也是可迭代的,但是可迭代器不是迭代器。
Luciano Ramalho,流利的Python。
回答 10
在处理迭代器和迭代器之前,决定迭代器和迭代器的主要因素是顺序
序列:序列是数据的集合
可迭代:可迭代是支持__iter__
方法的序列类型对象。
Iter方法:Iter方法将序列作为输入并创建一个称为迭代器的对象
迭代器:迭代器是调用next方法并遍历整个序列的对象。在调用下一个方法时,它返回当前遍历的对象。
例:
x=[1,2,3,4]
x是一个由数据收集组成的序列
y=iter(x)
调用iter(x)
时,仅当x对象具有iter方法时才返回迭代器,否则会引发异常。如果返回迭代器,则按如下方式分配y:
y=[1,2,3,4]
由于y是迭代器,因此它支持next()
方法
调用next方法时,它会一步一步返回列表的各个元素。
返回序列的最后一个元素后,如果再次调用下一个方法,则会引发StopIteration错误
例:
>>> y.next()
1
>>> y.next()
2
>>> y.next()
3
>>> y.next()
4
>>> y.next()
StopIteration
回答 11
在Python中,一切都是对象。如果说一个对象是可迭代的,则意味着您可以将对象作为一个集合逐步进行(即迭代)。
例如,数组是可迭代的。您可以使用for循环遍历它们,并从索引0到索引n,n是数组对象的长度减去1。
字典(键/值对,也称为关联数组)也是可迭代的。您可以逐步浏览他们的键。
显然,不是集合的对象是不可迭代的。例如,布尔对象只有一个值为True或False。它不是可迭代的(它是一个可迭代的对象是没有意义的)。