Python中的“iterable”、“iterator”和“iteration”是什么?它们是如何定义的?
当前回答
迭代器是实现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
迭代器会耗尽。这意味着在你遍历项目之后,你不能重复,你必须创建一个新对象。假设你有一个类,它包含cities属性,你想要遍历。
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的实例是一个迭代器。然而,如果你想在城市上重复,你必须创建一个新对象,这是一个昂贵的操作。你可以把这个类分成两个类:一个返回城市,第二个返回一个迭代器,它将城市作为初始参数。
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
现在如果我们需要创建一个新的迭代器,我们不需要再次创建数据,也就是城市。我们创建了cities对象并将其传递给迭代器。但我们仍在做额外的工作。我们可以通过只创建一个类来实现这一点。
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
迭代器有__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
其他回答
iterable是一个具有__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
其他人已经全面地解释了什么是iterable和iterator,所以我将尝试对生成器做同样的事情。
恕我直言,理解生成器的主要问题是“生成器”这个词的混淆用法,因为这个词有两种不同的含义:
作为创建(生成)迭代器的工具, 以返回迭代器的函数形式(即在函数体中包含yield语句), 以生成器表达式的形式 作为使用该工具的结果,即结果迭代器。 (在这个意思中,生成器是迭代器的一种特殊形式——“generator”这个词指出了这个迭代器是如何创建的。)
Generator作为第一种工具:
In[2]: def my_generator():
...: yield 100
...: yield 200
In[3]: my_generator
输出[3]:<function __main__.my_generator()> .my_generator(
In[4]: type(my_generator)
[4]:函数
生成器作为使用此工具的结果(即迭代器):
In[5]: my_iterator = my_generator()
In[6]: my_iterator
输出[6]:<生成器对象my_generator at 0x00000000053EAE48>
In[7]: type(my_iterator)
[7]:发电机
Generator作为第二种类型的工具-与该工具的结果迭代器难以区分:
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)
[10]:发电机
我不认为你能得到比文档更简单的东西,但我会尝试:
Iterable是可以被迭代的对象。在实践中,它通常是指一个序列,例如,有开始和结束的东西,以及一些贯穿其中所有项目的方法。 您可以将Iterator视为一个辅助伪方法(或伪属性),它给出(或保存)可迭代对象中的下一个(或第一个)项。(实际上它只是一个定义next()方法的对象) 《韦氏词典》对迭代这个词的定义可能是最好的解释:
B:重复指定的计算机指令序列 次数或直到满足条件-比较递归
迭代是一个通用术语,指一个接一个地获取某物的每一项。任何时候使用循环,显式或隐式,遍历一组项,这就是迭代。
在Python中,iterable和iterator有特定的含义。
iterable是一个具有__iter__方法的对象,该方法返回一个迭代器,或者定义了__getitem__方法,该方法可以接受从0开始的顺序索引(并在索引不再有效时引发IndexError)。iterable是一个你可以从中获取迭代器的对象。
迭代器是具有next (Python 2)或__next__ (Python 3)方法的对象。
无论何时在Python中使用for循环、map或列表推导式等,都会自动调用下一个方法从迭代器中获取每一项,从而完成迭代过程。
开始学习的一个好地方是教程的迭代器部分和标准类型页面的迭代器类型部分。在您理解了基础知识之后,请尝试函数式编程HOWTO中的迭代器部分。
上面的答案很好,但就我所见,对像我这样的人来说,没有足够的区别。
此外,人们倾向于把“X是一个具有__foo__()方法的对象”这样的定义放在前面,从而变得“过于python化”。这样的定义是正确的——它们基于duck-typing哲学,但是在试图理解概念的简单性时,对方法的关注往往会变得偏颇。
所以我添加了我的版本。
在自然语言中,
迭代是在一行元素中每次取一个元素的过程。
在Python中,
Iterable是一个对象,它是可迭代的,简单地说 它可以在迭代中使用,例如使用for循环。如何?通过使用迭代器。 我将在下面解释。 ... 而iterator是一个对象,它定义了如何实际执行 迭代——特别是下一个元素是什么。这就是为什么它一定是 next()方法。
迭代器本身也是可迭代的,区别在于它们的__iter__()方法返回相同的对象(self),而不管它的项是否已被之前对next()的调用所消耗。
那么,当Python解释器在obj: statement中看到for x时,它会怎么想?
看,一个for循环。看起来像是迭代器的工作…让我们买一个. ... 这里有个obj,我们来问他。 " obj先生,你有迭代器吗"(…调用iter(obj),它调用 Obj.__iter__(),它愉快地分发了一个闪亮的新迭代器_i。) 好吧,这很简单……让我们开始迭代。(x = _i.next()…X = _i.next()…
因为Mr. obj在这个测试中成功了(通过让某个方法返回一个有效的迭代器),我们用一个形容词来奖励他:你现在可以称他为“可迭代的Mr. obj”。
然而,在简单的情况下,将迭代器和iterable分开使用通常没有什么好处。所以你只定义了一个对象,它也是它自己的迭代器。(Python并不真正关心obj传递的_i是不是那么闪亮,而只是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()
不过,在有些情况下,将迭代器与可迭代对象分开可以带来好处,比如当你想要有一行项,但有更多的“游标”时。例如,当您想要处理“当前”和“即将”元素时,可以为这两个元素使用单独的迭代器。或者从一个巨大的列表中抽取多个线程:每个线程都有自己的迭代器来遍历所有项。请看上面@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()
注:
I'll repeat again: iterator is not iterable. Iterator cannot be used as a "source" in for loop. What for loop primarily needs is __iter__() (that returns something with next()). Of course, for is not the only iteration loop, so above applies to some other constructs as well (while...). Iterator's next() can throw StopIteration to stop iteration. Does not have to, though, it can iterate forever or use other means. In the above "thought process", _i does not really exist. I've made up that name. There's a small change in Python 3.x: next() method (not the built-in) now must be called __next__(). Yes, it should have been like that all along. You can also think of it like this: iterable has the data, iterator pulls the next item
免责声明:我不是任何Python解释器的开发人员,所以我真的不知道解释器“在想什么”。上面的思考仅仅是我从其他解释、实验和一个Python新手的实际经验中对这个主题的理解。
推荐文章
- 有没有办法在python中做HTTP PUT
- “foo Is None”和“foo == None”之间有什么区别吗?
- 类没有对象成员
- Django模型“没有显式声明app_label”
- 熊猫能自动从CSV文件中读取日期吗?
- 在python中zip的逆函数是什么?
- 有效的方法应用多个过滤器的熊猫数据框架或系列
- 如何检索插入id后插入行在SQLite使用Python?
- 我如何在Django中添加一个CharField占位符?
- 如何在Python中获取当前执行文件的路径?
- 我如何得到“id”后插入到MySQL数据库与Python?
- super()失败,错误:TypeError "参数1必须是类型,而不是classobj"当父不继承对象
- Python内存泄漏
- 实现嵌套字典的最佳方法是什么?
- 如何在tensorflow中获得当前可用的gpu ?