Python中“iterable”,“iterator”和“iteration”的最基本定义是什么?
我已阅读多个定义,但我无法确定其确切含义,因为它仍然不会沉入其中。
有人可以帮助我解释外行人的3个定义吗?
答案 0 :(得分:450)
迭代是一个接一个地取出每件物品的通用术语。无论何时使用显式或隐式循环来遍历一组项目,即迭代。
在Python中,可迭代和迭代器具有特定含义。
可迭代是一个具有__iter__
方法的对象,该方法返回迭代器,或者定义可以采用顺序的__getitem__
方法索引从零开始(当索引不再有效时引发IndexError
)。所以 iterable 是一个可以从中获取迭代器的对象。
迭代器是一个具有next
(Python 2)或__next__
(Python 3)方法的对象。
每当您在Python中使用for
循环或map
或列表推导等时,系统会自动调用next
方法以从中获取每个项目迭代器,因此经历了迭代的过程。
开始学习的好地方是iterators section of the tutorial和iterator types section of the standard types page。了解基础知识后,请尝试iterators section of the Functional Programming HOWTO。
答案 1 :(得分:292)
以下是我在Python课程教学中使用的解释:
ITERABLE是:
for x in iterable: ...
或iter()
拨打任何可以返回ITERATOR的任何内容:iter(obj)
或__iter__
的对象,它返回一个新的ITERATOR,
或者它可能具有适合索引查找的__getitem__
方法。ITERATOR是一个对象:
__next__
方法:
StopIteration
__iter__
的{{1}}方法。注意:
self
方法在Python 2中拼写为__next__
,并且next
在传递给它的对象上调用该方法。例如:
next()
答案 2 :(得分:92)
上述答案很棒,但正如我所看到的大多数情况一样,不要强调区别对于像我这样的人来说。
此外,人们倾向于通过像“X是具有__foo__()
方法的对象”之类的定义来获得“过于Pythonic”。这样的定义是正确的 - 它们基于鸭子类型的哲学,但是当试图以简单的方式理解这个概念时,对方法的关注往往会介入。
所以我添加了我的版本。
用自然语言,
在Python中,
iterable 是一个可以迭代的对象,简单地说,意味着
它可以在迭代中使用,例如使用for
循环。怎么样?使用迭代器。
我将在下面解释。
...而迭代器是一个定义如何实际执行的对象
迭代 - 特别是下一个元素是什么。这就是它必须拥有的原因
next()
方法。
迭代器本身也是可迭代的,区别在于它们的__iter__()
方法返回相同的对象(self
),无论先前调用{{1}是否已使用它的项目}。
那么Python解释器在看到next()
语句时会怎么想?
看,
for x in obj:
循环。看起来像迭代器的工作......让我们得到一个。 ... 有这个for
家伙,所以让我们问他。“
obj
先生,你有你的迭代器吗?” (...调用obj
,调用iter(obj)
,愉快地发出了一个闪亮的新迭代器obj.__iter__()
。)好的,这很容易......让我们开始迭代吧。 (
_i
...x = _i.next()
...)
由于x = _i.next()
先生成功完成了这个测试(通过某种方法返回一个有效的迭代器),我们用形容词奖励他:你现在可以称他为“可迭代先生obj
”。
但是,在简单的情况下,通常不会分别使用迭代器和迭代。因此,您只定义一个对象,它也是它自己的迭代器。 (Python并不关心obj
发出的_i
并不是那么闪亮,而只是obj
本身。)
这就是为什么在我见过的大多数例子中(以及一次又一次令我困惑的事情), 你可以看到:
obj
而不是
class IterableExample(object):
def __iter__(self):
return self
def next(self):
pass
但是,有些情况下,您可以从迭代器中分离迭代器,例如当您想拥有一行项目,但需要更多“游标”时。例如,当您想使用“当前”和“即将到来”元素时,可以为两者分别设置迭代器。或者从一个巨大的列表中拉出多个线程:每个线程都可以拥有自己的迭代器来遍历所有项目。请参阅上面的@Raymond's和@glglgl's解答。
想象一下你能做什么:
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
...)。
Iterator的while
可以抛出StopIteration来停止迭代。不必,
但是,它可以永久迭代或使用其他方式。
在上面的“思考过程”中,next()
并不存在。我已经填了这个名字。
Python 3.x中有一个小变化:_i
方法(不是内置的)现在
必须被称为next()
。是的,它应该一直都是这样。
你也可以这样想:iterable有数据,迭代器拉下一个 项目
免责声明:我不是任何Python解释器的开发者,所以我真的不知道解释器“认为”是什么。上面的思考只是演示了我如何从Python新手的其他解释,实验和现实经验中理解这个主题。
答案 3 :(得分:20)
iterable是一个具有__iter__()
方法的对象。它可能会迭代几次,例如list()
和tuple()
s。
迭代器是迭代的对象。它由__iter__()
方法返回,通过自己的__iter__()
方法返回自身,并在3.x中使用next()
方法(__next__()
。)
迭代是调用此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
。
示例:
{{1}}
答案 4 :(得分:9)
我不知道它是否对任何人有帮助,但我总是喜欢想象一下我头脑中的概念以便更好地理解它们。因此,当我有一个小儿子时,我用砖和白纸可视化迭代/迭代器概念。
假设我们在黑暗的房间和地板上,我们的儿子有砖块。不同尺寸,颜色的砖现在无关紧要。假设我们有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
>>>
不知道它是否有帮助,但它对我有帮助。如果有人能够确认/纠正这个概念的可视化,我将不胜感激。这将有助于我了解更多信息。
答案 5 :(得分:7)
这是我的备忘单:
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__
方法不一定是迭代器吗?答案 6 :(得分:3)
我不认为你可以比documentation更简单,但是我会尝试:
您可以将 Iterator 视为辅助伪方法(或伪属性),它提供(或保留) iterable中的下一个(或第一个)项。 (实际上,它只是一个定义方法next()
)
迭代:
b:重复指定的一系列计算机指令 次数或直到满足条件 - 比较递归
答案 7 :(得分:3)
Iterable : - 可迭代的东西是可迭代的;像列表,字符串等序列
它还有__getItem__()
方法或返回迭代器的iter()
函数。
迭代器: - 当我们从迭代的iter()
方法中获取迭代器对象时;我们调用__next__()
方法(在python3中)或简单地next()
(在python2中)来逐个获取元素。此类的此类或实例称为迭代器。
来自docs: -
迭代器的使用遍及并统一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
答案 8 :(得分:2)
iterable = [1, 2]
iterator = iter(iterable)
print(iterator.__next__())
print(iterator.__next__())
所以,
iterable
是对象,可以循环。例如list,string,tuple等。
使用iter
对象上的iterable
函数将返回迭代器对象。
现在这个迭代器对象的方法名为__next__
(在Python 3中,或者只是Python 2中的next
),您可以通过它访问每个可迭代的元素。
所以, 上面代码的输出将是:
1
2
答案 9 :(得分:1)
在处理iterables和迭代器之前,决定迭代和迭代器的主要因素是序列
序列:序列是数据的集合
Iterable:Iterable是支持Iter方法的序列类型对象。
Iter方法:Iter方法将sequence作为输入并创建一个称为迭代器的对象
Iterator:Iterator是调用next方法并横向遍历序列的对象。在调用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
答案 10 :(得分:1)
可迭代对象具有
__iter__
方法,该方法每次都实例化一个新的迭代器。迭代器实现返回单个项目的
__next__
方法和返回__iter__
的{{1}}方法。因此,迭代器也是可迭代的,但是可迭代器不是迭代器。
Luciano Ramalho,流利的Python。
答案 11 :(得分:1)
迭代器是实现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 类的实例是一个迭代器。但是,如果您想重复城市,则必须创建一个新对象,这是一项昂贵的操作。您可以将类分为 2 个类:一个返回城市,第二个返回一个迭代器,该迭代器将城市作为 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
现在如果我们需要创建一个新的迭代器,我们就不必再次创建数据,即城市。我们创建了城市对象并将其传递给迭代器。但我们仍在做额外的工作。我们可以通过只创建一个类来实现这一点。
Iterable 是一个 Python 对象,它实现了 iterable 协议。它只需要返回迭代器对象的新实例的 __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
答案 12 :(得分:1)
要查看对象是否有这个方法iter(),我们可以使用下面的函数。
function* parser(some_string) {
let stack = "", pars = 0;
for (let i = 0; i < some_string.length; i++) {
if (some_string[i] == "(") {
if ((pars == 0) && (stack.length > 0)) {
yield stack;
stack = "";
}
stack += some_string[i];
pars += 1;
} else if (some_string[i] == ")") {
stack += some_string[i];
pars -= 1;
if ((pars == 0) && (stack.length > 0)) {
yield stack;
stack = "";
}
} else if (i == some_string.length - 1) {
if (stack.length > 0) {
yield stack;
stack = "";
}
} else {
stack += some_string[i];
}
}
}
let string = "foo(bar)baz(blim)(hhh(kkk)thfgg)";
const it = parser(string);
for(item of it) {
console.log(item);
}
输出
ls = ['hello','bye']
print(dir(ls))
如您所见,iter() 表示它是一个可迭代对象,但不包含 next() 方法,这是迭代器对象
每当您在 Python 中使用 for 循环或映射或列表推导式时,都会自动调用 next 方法以从迭代中获取每个项目
答案 13 :(得分:0)
其他人已经全面解释了什么是 iterable 和 iterator ,所以我将尝试使用 generators 做同样的事情。>
恕我直言,理解生成器的主要问题是混淆了“ generator”一词的使用,因为该词有两种不同的含义:
yield
语句)Generator作为1 st 类型的工具:
In[2]: def my_generator():
...: yield 100
...: yield 200
In[3]: my_generator
Out[3]: <function __main__.my_generator()>
In[4]: type(my_generator)
Out[4]: function
生成器作为使用此工具的结果(即 iterator ):
In[5]: my_iterator = my_generator()
In[6]: my_iterator
Out[6]: <generator object my_generator at 0x00000000053EAE48>
In[7]: type(my_iterator)
Out[7]: generator
Generator作为2 nd 类型的工具 –与该工具的结果迭代器没有区别:
In[8]: my_gen_expression = (2 * i for i in (10, 20))
In[9]: my_gen_expression
Out[9]: <generator object <genexpr> at 0x000000000542C048>
In[10]: type(my_gen_expression)
Out[10]: generator
答案 14 :(得分:0)
这是另一个使用 collections.abc
的视图。此视图可能在第二次或以后有用。
从 collections.abc
我们可以看到以下层次结构:
builtins.object
Iterable
Iterator
Generator
即Generator 派生自 Iterator 派生自 Iterable 派生自基础对象。
因此,
[1, 2, 3]
和 range(10)
是可迭代对象,但不是迭代器。 x = iter([1, 2, 3])
是一个迭代器和一个迭代器。iter()
会返回自身。因此,如果 it
是迭代器,则 iter(it) is it
为 True。[2 * x for x in nums]
这样的列表推导式或像 for x in nums:
这样的 for 循环,就像在可迭代对象 (iter()
) 上调用 nums
然后进行迭代一样使用该迭代器在 nums
上。因此,以下所有内容在功能上都是等效的(例如,nums=[1, 2, 3]
):
for x in nums:
for x in iter(nums):
for x in iter(iter(nums))
:for x in iter(iter(iter(iter(iter(nums))))):
答案 15 :(得分:0)
对我来说,Python 的 glossery 对这些问题最有帮助,例如对于迭代它说:
<块引用>一个能够一次返回一个成员的对象。可迭代对象的示例包括所有序列类型(例如列表、字符串和元组)和一些非序列类型,例如 dict、文件对象以及您使用 iter() 方法定义的任何类的对象或使用实现 Sequence 语义的 getitem() 方法。
<块引用>可迭代对象可用于 for 循环和许多其他需要序列的地方(zip()、map()……)。当可迭代对象作为参数传递给内置函数 iter() 时,它会返回该对象的迭代器。此迭代器适用于对一组值进行一次传递。使用可迭代对象时,通常不需要调用 iter() 或自己处理迭代器对象。 for 语句会自动为您执行此操作,创建一个临时未命名变量以在循环期间保存迭代器。另见迭代器、序列和生成器。
答案 16 :(得分:-3)
示例如下: 类 Square(): def init(self, max): self.max =max 自身力量=0 def iter(self): 回归自我 def next(self):
if(self.power<=self.max):
result = 2**self.power
self.power +=1
return result
else:
raise StopIteration
square = Square(5) 对于我在广场: 打印(i)
答案 17 :(得分:-6)
在Python中,一切都是对象。当一个对象被称为可迭代时,这意味着您可以将对象作为集合单步执行(即迭代)。
例如,数组是可迭代的。您可以使用for循环逐步执行它们,并从索引0转到索引n,n是数组对象的长度减去1。
字典(键/值对,也称为关联数组)也是可迭代的。你可以逐步完成他们的钥匙。
显然,不是集合的对象是不可迭代的。例如,bool对象只有一个值,True或False。它不可迭代(它是一个可迭代的对象没有意义。)