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

迭代对象有一个__iter__方法,每次都会实例化一个新的迭代器。 迭代器实现了一个__next__方法返回单个项,以及一个__iter__方法返回self。 因此,迭代器也是可迭代的,但可迭代的不是迭代器。

卢西亚诺·拉马略,流利的蟒蛇。

我不知道这是否对任何人都有帮助,但我总是喜欢在脑子里把概念形象化,以便更好地理解它们。所以,就像我有一个小儿子一样,我用砖块和白纸来想象迭代器/迭代器的概念。

Suppose we are in the dark room and on the floor we have bricks for my son. Bricks of different size, color, does not matter now. Suppose we have 5 bricks like those. Those 5 bricks can be described as an object – let’s say bricks kit. We can do many things with this bricks kit – can take one and then take second and then third, can change places of bricks, put first brick above the second. We can do many sorts of things with those. Therefore this bricks kit is an iterable object or sequence as we can go through each brick and do something with it. We can only do it like my little son – we can play with one brick at a time. So again I imagine myself this bricks kit to be an iterable.

现在请记住,我们是在一个黑暗的房间里。或者几乎是黑暗的。问题是我们看不清这些砖,它们是什么颜色,什么形状等等。所以即使我们想对它们做些什么——也就是迭代它们——我们也不知道要做什么,怎么做,因为太暗了。

我们能做的是靠近第一块砖-作为一个砖套件的元素-我们可以放一张白色荧光纸,以便我们看到第一块砖元素在哪里。每次我们从工具箱中取出一块砖,我们就把这张白纸换成下一块砖,这样就能在黑暗的房间里看到它。这张白纸只不过是一个迭代器。它也是一个对象。而是一个我们可以使用可迭代对象中的元素的对象——bricks工具包。

顺便说一下,这解释了我早期的错误,当我在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
>>>

不知道有没有帮助,但对我有帮助。如果有人能确认/纠正这个概念的可视化,我会很感激。这会帮助我了解更多。

Iterable:-可迭代的东西是可迭代的;比如序列,比如列表,字符串等等。 它也有__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

其他人已经全面地解释了什么是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]:发电机