the*_*dad 408 python iteration iterator iterable terminology
Python中"iterable","iterator"和"iteration"的最基本定义是什么?
我已阅读多个定义,但我无法确定其确切含义,因为它仍然不会沉入其中.
有人可以帮助我解释外行人的3个定义吗?
agf*_*agf 491
迭代是一个接一个地取出每个项目的通用术语.任何时候使用循环(显式或隐式)来遍历一组项目,即迭代.
在Python中,iterable和iterator具有特定的含义.
一个迭代是具有对象__iter__
返回一个方法迭代,或者其限定__getitem__
,可以采取顺序索引从零启动方法(并发出IndexError
时,索引不再有效).因此,iterable是一个可以从中获取迭代器的对象.
一个迭代器是具有一个对象next
(Python的2)或__next__
(Python 3的)方法.
无论何时在Python中使用for
循环,或者map
列表推导等,next
都会自动调用该方法以从迭代器中获取每个项目,从而完成迭代过程.
开始学习的好地方是教程的迭代器部分和标准类型页面的迭代器类型部分.在了解了基础知识之后,请尝试使用Functional Programming HOWTO的迭代器部分.
Ray*_*ger 312
这是我在教授Python类时使用的解释:
ITERABLE是:
for x in iterable: ...
或iter()
都会返回一个ITERATOR: iter(obj)
或__iter__
返回一个新的ITERATOR,或者它可能有一个__getitem__
适合索引查找的方法.ITERATOR是一个对象:
__next__
方法:
StopIteration
__iter__
返回的方法self
).笔记:
__next__
Python 3中的方法拼写next
在Python 2中,并且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
Run Code Online (Sandbox Code Playgroud)
Alo*_*dal 94
上面的答案很棒,但正如我所见过的大部分内容,不要强调像我这样的人的区别.
此外,人们倾向于通过像"X是一个有__foo__()
方法的对象"之类的定义来获得"过于Pythonic" .这样的定义是正确的 - 它们基于鸭子类型的哲学,但是当试图在简单性中理解概念时,对方法的关注往往会介于两者之间.
所以我添加了我的版本.
用自然语言
在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()
...)
由于先生obj
成功完成了这个测试(通过某种方法返回一个有效的迭代器),我们用形容词奖励他:你现在可以称他为"可迭代的先生obj
".
但是,在简单的情况下,通常不会分别使用迭代器和迭代.所以你只定义了一个对象,它也是它自己的迭代器.(Python并不真正关心_i
发布的obj
并不是那么闪亮,而是它obj
本身.)
这就是为什么在我见过的大多数例子中(以及令我一直困惑的东西),你可以看到:
class IterableExample(object):
def __iter__(self):
return self
def next(self):
pass
Run Code Online (Sandbox Code Playgroud)
代替
class Iterator(object):
def next(self):
pass
class Iterable(object):
def __iter__(self):
return Iterator()
Run Code Online (Sandbox Code Playgroud)
但是,有些情况下,您可以从迭代器中分离迭代器,例如当您想拥有一行项目,但更多的是"游标"时.例如,当您想使用"当前"和"即将到来"元素时,可以为两者分别设置迭代器.或者从一个巨大的列表中拉出多个线程:每个线程都可以拥有自己的迭代器来遍历所有项目.请参阅上面的@ Raymond和@ 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()
Run Code Online (Sandbox Code Playgroud)
笔记:
我将再次重复:迭代器不可迭代.迭代器不能用作for
循环中的"源" .for
主要需要的是什么循环__iter__()
(返回一些东西next()
).
当然,for
不是唯一的迭代循环,所以上面也适用于其他一些结构(while
...).
迭代器next()
可以抛出StopIteration来停止迭代.但是,它不必永远迭代或使用其他方法.
在上面的"思考过程"中,_i
并不存在.我已经编造了这个名字.
Python 3.x中有一个小的变化:next()
现在必须调用方法(不是内置的)__next__()
.是的,一直都应该这样.
你也可以这样想:iterable有数据,iterator拉下一个项目
免责声明:我不是任何Python解释器的开发人员,所以我真的不知道解释器"思考"了什么.上面的思考只是演示了我如何从Python新手的其他解释,实验和现实生活经验中理解这个主题.
glg*_*lgl 21
iterable是具有__iter__()
方法的对象.它可能会迭代几次,例如list()
s和tuple()
s.
迭代器是迭代的对象.它由一个__iter__()
方法返回,通过自己的__iter__()
方法返回自己,并有一个next()
方法(__next__()
在3.x中).
迭代是调用此next()
resp 的过程.__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
Run Code Online (Sandbox Code Playgroud)
我不知道它是否对任何人有所帮助,但我总是喜欢想象一下我头脑中的概念,以便更好地理解它们.因此,当我有一个小儿子时,我用砖和白纸可视化可迭代/迭代器概念.
假设我们在黑暗的房间和地板上,我们的儿子都有砖块.不同尺寸,颜色的砖现在无关紧要.假设我们有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
Run Code Online (Sandbox Code Playgroud)
这里的清单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
>>>
Run Code Online (Sandbox Code Playgroud)
不知道它是否有帮助,但它对我有帮助.如果有人能够确认/纠正这个概念的可视化,我将不胜感激.这将有助于我了解更多.
这是我的备忘单:
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 +-+
Run Code Online (Sandbox Code Playgroud)
测验:你看到了......
__iter__()
方法可以实现为生成器吗?__next__
方法不一定是迭代器吗?可迭代: -这是迭代的迭代; 例如列表,字符串等序列。它也具有__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
Run Code Online (Sandbox Code Playgroud)
例如:
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
Run Code Online (Sandbox Code Playgroud)
Iterables有一个
__iter__
方法,每次都实例化一个新的迭代器。迭代器实现了一个
__next__
返回单个项目的__iter__
方法,以及一个返回self
.因此,迭代器也是可迭代的,但可迭代的不是迭代器。
Luciano Ramalho,流利的 Python。
迭代器是实现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
Run Code Online (Sandbox Code Playgroud)
迭代器会耗尽。这意味着在迭代项目后,您不能重复,您必须创建一个新对象。假设您有一个类,其中包含城市属性并且您想要迭代。
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
Run Code Online (Sandbox Code Playgroud)
Cities 类的实例是一个迭代器。但是,如果您想在城市上重复,则必须创建一个新对象,这是一项昂贵的操作。您可以将该类分为 2 个类:一个返回城市,第二个返回一个迭代器,该迭代器将城市作为初始化参数。
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
Run Code Online (Sandbox Code Playgroud)
现在如果我们需要创建一个新的迭代器,我们不必再次创建数据,即城市。我们创建城市对象并将其传递给迭代器。但我们仍在做额外的工作。我们可以通过仅创建一个类来实现这一点。
Iterable是一个实现了iterable 协议的Python 对象。它只需要__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
Run Code Online (Sandbox Code Playgroud)
迭代器有__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
Run Code Online (Sandbox Code Playgroud)