Python 迭代器(iterator)与生成器(generator)

一、概念


    容器(container):容器是一种把多个元素组织在一起的数据结构,将大部分数据保存在内存中

    可迭代对象(Iterable):通俗的说就是在数据类型对象中,只要包含__iter__()

    迭代器(Iterator):通俗来讲任何具有__next__()方法的对象都是迭代器

    生成器(generator):使用了 yield 的函数被称为生成器(generator)。是一种特殊的、一种更为高级的、更为优雅的迭代器。返回可以迭代对象的函数


二、容器( Container)

    容器中的元素可以逐个地迭代获取,可以用in, not in关键字判断元素是否包含在容器中。通常这类数据结构把大部分的元素存储在内存中(也有一些特例,并不是所有的元素都放在内存,比如迭代器和生成器对象),在Python中,常见的容器对象有:

    list, deque, ….

    set, frozensets, ….

    dict, defaultdict, OrderedDict, Counter, ….

    tuple, namedtuple, …

    str

    容器相对来说很好理解,因为你可以把它当成生活中的箱子、房子、船等等里面可以塞任何东西。从技术角度来说,当通过判断一个对象是否包含某个元素来确定它是否为一个容器 

Python 迭代器(iterator)与生成器(generator)_第1张图片
容器示例

    尽管绝大多数容器都提供了某种方式来获取其中的每一个元素,但这并不是容器本身提供的能力,而是可迭代对象赋予了容器这种能力,当然并不是所有的容器都是可迭代的,比如:Bloom filter,虽然Bloom filter可以用来检测某个元素是否包含在容器中,但是并不能从容器中获取其中的每一个值,因为Bloom filter压根就没把元素存储在容器中,而是通过一个散列函数映射成一个值保存在数组中。参考:Python3 迭代器和生成器 - 迷鸟归林 - 博客园


三、迭代器(Iterator)

    迭代器是 Python 最强大的功能之一,是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。迭代器有两个基本的方法:iter() 和 next()

    字符串,列表或元组对象都可用于创建迭代器,以下示例:

Python 迭代器(iterator)与生成器(generator)_第2张图片

    迭代器调用__next__()方法可以获取下一个值, 实际调用过程如下:

Python 迭代器(iterator)与生成器(generator)_第3张图片
引用过程图

    那么如何判断一个对象是否是可迭代呢?可迭代对象可以为任意对象,不一定非得是基本数据结构,只要这个对象可以返回一个iterator, 可以使用 collections 模块的 Iterable 类型判断:

Python 迭代器(iterator)与生成器(generator)_第4张图片

    把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__()与__next__() 。如果你已经了解的面向对象编程,就知道类都有一个构造函数,Python的构造函数为__init__(), 它会在对象初始化的时候执行。__iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了__next__() 方法并通过StopIteration异常标识迭代的完成。

    下面我们来创建一个迭代器:

Python 迭代器(iterator)与生成器(generator)_第5张图片

    StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 __next__() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。

    可迭代对象: 本质是提供一个中间人,遍历的时候, 需要数据的时候, 获取这个对象的迭代器, 然后通过迭代器依次获取对象中的数据。具备了一个__iter__ 方法的对象就是一个可迭代对象。通过iter方法获得可迭代对象的迭代器, 然后对迭代器使用next() 方法, 获取下一个数据。

迭代器的作用:
    迭代器最核心的功能是通过next()函数的调用来返回下一个数据值。如果每次返回的数据值不是在一个已有的数据集合中读取的,而是通过程序按照一定的规律计算生成的 * 可以节省内存和存储空间。如果我们产生的数据很多, 数据量很大的话,很容易把进程跑死或者把服务器跑崩溃。


四、生成器(Generator)

    在Python中,使用了 yield 的函数被称为生成器(generator)。跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。调用一个生成器函数,返回的是一个迭代器对象。

    生成器是一种特殊的迭代器, 保存当前运行的状态。在Python中有两种类型的生成器:生成器表达式以及生成器函数。生成器函数就是包含 yield 参数的函数。生成器表达式与列表解析式类似。

先看第一种生成器表达式:

第一种方法很简单,只要把一个列表生成式的 [ ] 改成 ( )
L = [x*2 for x in range(5)]
print(L)
# 输出:[0, 2, 4, 6, 8]
G = (x*2 for x in range(5))
print(G)
# 输出: at 0x000001CDCF78B8C8>

print("length L:", type(L))  # 输出列表的长度 10
print("length G:", len(G))  # TypeError: object of type 'generator' has no len(),因为生成器不能直接给出长度!!!
# 注意点:二者输出等价,不过 G 是在运行时开辟内存,而 L 是直接开辟内存


第二种生成器函数:

    第二种方法使用 yeild 函数 ,在函数( __ next __)中使用 yeild 关键字,属于生成器函数。在一般函数中使用 yield 关键字,可以实现一个最简单的生成器,此时这个函数变成一个生成器函数。yield  return 返回相同的值,区别在于return返回后,函数状态终止,而yield会保存当前函数的执行状态,在返回后,函数又回到之前保存的状态继续执行。

    声明:1.任意生成器都是迭代器(反过来不成立)2.任意生成器,都是一个可以延迟创建值的工厂

    以下实例使用 yield 实现斐波那契数列:

Python 迭代器(iterator)与生成器(generator)_第6张图片

那么生成器函数与一般函数的区别:

1.生成器函数包含一个或者多个yield
2.调用生成器函数时,函数将返回一个对象,延迟暂停向下执行
3.__iter__()和__next__()方法等是自动实现,通过next()方法进行迭代对象
4.一旦函数 使用关键字 yield,函数会暂停,控制权返回调用者,局部变量和它们的状态会被保存,直到下一次调用
5.函数终止的时候,StopIteraion会被自动抛出 

总之,生成器是Python中一种非常强大的特性,它让我们能够编写更加简洁的代码,同时也更加节省内存,使用CPU也更加高效。

                                                                    --大多数人想要改造这个世界,但却罕有人想改造自己--

你可能感兴趣的:(Python 迭代器(iterator)与生成器(generator))