[TimLinux] Python 迭代器(iterator)和生成器(generator)

1. 可迭代对象

from collection import Iterable


class Iterable(metaclass=ABCMeta):
    ...
    def __iter__(self):  # 只实现了__iter__ 方法
        while False:
            yield None

能够在 for ... in obj:中使用的对象(obj)就是一个可迭代对象。

2. 迭代器

from collections import Iterator


class Iterator(Iterable):  # Iterable的子类
    ...
    def __next__(self):  # 实现了 __next__
        raise StopIteration

    def __iter__(self):  # 也实现了 __iter__
        return self

能够使用.next() 或者 .__next__() 方法,在没有下一个元素时,返回 StopIteration 异常的对象,都是迭代器,可迭代对象转换成迭代器的方法是: iter(obj) 返回的就是一个迭代器。

>>> a = []
>>> a
[]
>>> s = iter(a)
>>> s
<list_iterator object at 0x7feac859b048>
>>> s.next() # 这个方法不存在,抛出的是属性错误异常
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'list_iterator' object has no attribute 'next'
>>> s.__next__
<method-wrapper '__next__' of list_iterator object at 0x7feac859b048>
>>> s.__next__()  # 这个方法存在,抛出的是 StopIteration 异常
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>

实现自己的迭代器:

class Reverse:
    def __init__(self, data):
        self.data = data
        self.index = len(data)

    def __iter__(self):
        return self

    def __next__(self):  # py2: next()方法
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]

rev = Reverse('timlinux')
for char in rev:
    print(char)

3. 生成器yield

生成器(generator)是用来构造迭代器的一种语法工具,通过使用 yield 关键字来代替 return,并自动构建好 __iter__() 和 __next__() 两个方法:

  • yield 关键字的位置将发生 return 操作
  • yield 关键字存在的函数中,将具有 __iter__, __next__ 函数
def reverse(data):
    max_len = len(data) - 1
    min_len = -1
    for index in range(max_len, min_len, -1):
        yield data[index]

x = reverse('timlinux')
dir(x)  # py3: 返回的对象有 __iter__, __next__ 方法
        # py2: 返回的对象有 __iter__, next 方法

列表生成式中的 [] 换成 (),得到的对象就不再是一个列表,而是一个生成器:

>>> L = [x*x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x*x for x in range(10))
>>> g
<generator object <genexpr> at 0x7f9a8dd48a00>

4. 场景

在使用中分配内存,而不是一次分配所有的内存。

猜你喜欢

转载自www.cnblogs.com/timlinux/p/9700691.html