python迭代器和生成器详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_42681866/article/details/83377892

前文

  迭代器(Iterator)和生成器(generator)是python众多强大的数据类型之一,两者的作用都是惰性计算,即不会立即产生所有结果,而是逐步产生一个个;两者的区别则是生成器本质上属于迭代器,生成器用于“凭空”生成元素,迭代器则是用于从集合中取出元素。斐波那契数列就是很好的例子,数列是个无穷数列,一个集合里放不下。不过通常来说,两者可以视作同一概念,即迭代器和生成器都可用于实现斐波那契数列。

迭代器和可迭代对象

  再讲解迭代器之前,需要先了解可迭代对象,这两者顾名思义,即都是针对一个可迭代的集合或者对象。前者相当于一个个迭代实例,后者相当于类,通过这个类可以衍生出各个迭代器。
  迭代器和可迭代对象应用里比较典型的就是python里的for…in…循环,在实现该循环之前,解释器会调用iter()函数把可迭代对象转换为迭代器,进而通过遍历取得每个数,如果对象非可迭代,则会报错:TypeError: ‘type’ object is not iterable
  如何查看某个对象是否为可迭代的?调用collections里的Iterable就行,代码如下:

>>> from collections import Iterable
>>> isinstance('abc', Iterable)
True
>>> isinstance([1,2,3], Iterable)
True
>>> isinstance(123, Iterable)
False

  从例子看出,int类型为非迭代对象。那如何实现可迭代对象?在类里定义__iter__函数就行了。目前常见的可迭代对象:list/tuple/set/str/dict等内置数据类型,如果查看源码发现其中都定义了__iter__魔法方法,接下来以自定义类来说明:
在这里插入图片描述

  可迭代对象就是定义__iter__函数,当用for…in…遍历可迭代对象时,会调用iter()方法,其本质就是通过__iter__函数不断产生一个个迭代器来帮助我们对其遍历,因此__iter__的代码通常是返回自身实例,代码如下:

class A:
	def __iter__(self):
		return self

iter()和next()

  在介绍完可迭代对象进而介绍迭代器之前,先介绍iter()和next()函数。如上文说讲,for…in…的本质是调用iter()将传入的迭代对象转换为迭代器,然后用next()一个个遍历出来,以元祖为例,如下:

t = (1,2,3,4)
iterator = iter(t)
next(iterator)

运行结果如下:
在这里插入图片描述

说明:

  1. iter(iterable)函数是把可迭代对象的迭代器取出来,内部是调用可迭代对象的__iter__方法,来取得迭代器的
  2. next(iterator)函数是通过迭代器取得下一个位置的值,内部是调用迭代器对象的__next__方法,来取得下一个位置的值
  3. 当我们已经迭代完最后一个数据之后,再次调用next()函数会抛出StopIteration的异常,来告诉我们所有数据都已迭代完成,不用再执行next()函数了。

注意: 检查对象x是否可迭代的,用iter(x)会更准确,调用iter(x),如果不可迭代,则报错TypeError: ‘type’ object is not iterable;为什么说会更准确?因为调用iter()方法会先查看对象是否定义__iter__,如果定义了则获取一个迭代器;如果没定义,但是实现了__getiterm__方法的话,python也会创建一个迭代器,此时即使没有__iter__方法,但也是可迭代的。举例如下:

class Test:
    def __init__(self, x):
        self.x = x

    def __getitem__(self, index): #该魔法方法是用于定义可用[]来访问键
        return self.x[index]

test = Test('abc')

for i in test:
    print(i)

返回结果:

>>>a
>>>b
>>>c

  可能有人会产生疑问,即因为传入的字符串所以该对象才是可迭代的,那我们取消定义__getitem__看看结果,如下图,会报错为该对象为非可迭代的。
在这里插入图片描述

迭代器Iterator

  迭代器的本质就是 一个实现了__iter__方法和__next__方法的对象,而其本身也是一个可迭代对象。
  所以,我们要想构造一个迭代器,就要实现它的__next__方法。但这还不够,python要求迭代器本身也是可迭代的,所以我们还要为迭代器实现__iter__方法,而__iter__方法要返回一个迭代器,迭代器自身正是一个迭代器,所以迭代器的__iter__方法返回自身即可。
  用迭代器来实现斐波那契数列:

class FibIterator(object):
    """斐波那契数列迭代器"""

    def __init__(self, n):
        # 记录生成fibonacci的数列的个数
        self.n = n
        # 记录当前遍历的下标
        self.current_index = 0
        # 记录fibonacci数列前面的两个值
        self.num1 = 0
        self.num2 = 1

    def __next__(self):
        """被next()函数调用来获取下一个数"""
        if self.current_index < self.n:
            num = self.num1
            self.num1, self.num2 = self.num2, self.num1 + self.num2
            self.current_index += 1
            return num
        else:
            raise StopIteration

    def __iter__(self):
        """迭代器的__iter__返回自身即可"""
        return self


if __name__ == '__main__':
    fib = FibIterator(10)
    for num in fib:
        print("  ", num, end="")

运行结果:

运行结果: 0 1 1 2 3 5 8 13 21 34

迭代器和可迭代对象总结

  可迭代对象:使用iter内置函数获取迭代器的对象,如果对象实现了__iter__方法,则是可迭代的;如果实现了__getitem__方法,并且从0开始索引,则也是可迭代的。
  迭代器:实现__iter__和__next__方法,__iter__返回自身,__next__返回下一个元素,当没有元素了,则返回StopIteration。
  迭代器总结如上,由于本文篇幅过大,生成器移到下一篇幅再行介绍。

猜你喜欢

转载自blog.csdn.net/weixin_42681866/article/details/83377892