首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python迭代器和生成器

Python迭代器和生成器

作者头像
oYabea
发布2020-09-07 11:47:54
3820
发布2020-09-07 11:47:54
举报
文章被收录于专栏:夏天爱西瓜夏天爱西瓜

Python的迭代器集成在语言之中,迭代器和生成器是Python中很重要的用法,本文将深入了解迭代器和生成器

首先,我们都知道for循环是一个基础迭代操作,大多数的容器对象都可以使用for循环,那么,我们从for循环开始

你有没有想过,for循环的内部实现原理呢?

其实,在Python中,for循环是对迭代器进行迭代的语法糖,内部运行机理就是:首先底层对循环对象实现迭代器包装(调用容器对象的__iter__方法)返回一个迭代器对象,每循环一步,就调用一次迭代器对象的__next__方法,直到循环结束时,自动处理StopIteration这个异常。

对于像list,dict等容器对象而言,都可以使用for循环,但是它们并不是迭代器,它们属于可迭代对象。

什么是可迭代对象呢?

最简单的解释:实现了迭代方法可以被迭代的对象,可以使用isinstance()方法进行判断。

举个例子:

In [1]: from collections import Iterable, Iterator
In [2]: a = [1, 2, 3]
In [3]: isinstance(a, Iterable)
Out[3]: True
In [4]: b = a.__iter__()
In [5]: isinstance(b, Iterator)
Out[5]: True

可迭代对象实现了__iter__方法,该方法返回一个迭代器对象。

以上,可以看到,在迭代过程中,实际调用了迭代器的__next__方法进行迭代。

那么,什么是迭代器?

实现了迭代器协议的对象就是迭代器,所谓的迭代器协议可以简单归纳为:

  1. 实现__iter__()方法,返回一个迭代器
  2. 实现next方法,返回当前元素并指向下一个元素,如果当前位置已无元素,则抛出StopIteration异常 。

迭代器和可迭代对象的区别是:迭代器可以使用next()方法不断调用并返回下一个值,除了调用可迭代对象的__iter__方法来将可迭代对象转换为迭代器以外,还可以使用iter()方法。

举个例子来验证以上说法:

In [1]: iter_data = iter([1, 2, 3])
In [2]: print(next(iter_data))
1
In [3]: print(next(iter_data))
2
In [4]: print(next(iter_data))
3
In [5]: print(next(iter_data))
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-16-425d66e859b8> in <module>
----> 1 print(next(iter_data))

为什么要用迭代器?

很重要的一点是,Python把迭代器内建在语言之中的,我们在遍历一个容器对象时并不需要去实现具体的遍历操作。

迭代器时一个惰性序列,仅仅在迭代至当前元素时才计算该元素的值,在此之前可以不存在,在此之后可以随时销毁,也就是说,在迭代过程中不是将所有元素一次性加载,这样便不需要考虑内存的问题。通过定义迭代器协议,我们可以随时实现一个迭代器。

什么时候用迭代器? 具体在什么场景下可以使用迭代器:

  • 数列的数据规模巨大
  • 数列有规律,但是不能使用列表推导式描述。

举个最简单的例子:

class Fib(object):
    def __init__(self):
        self._a = 0
        self._b = 1

    def __iter__(self):
        return self

    def __next__(self):
        self._a, self._b = self._b, self._a + self._b
        return self._a


if __name__ == '__main__':
    for index, item in enumerate(Fib()):
        print(item)
        if index >= 9:
            break

什么是生成器?

生成器,顾名思义,就是按照一定的模式生成一个序列,是一种高级的迭代器,Python中有一个专门的关键字(yield)来实现生成器。

如果一个函数,使用了yield语句,那么它就是一个生成器函数,当调用生成器函数函数时,它返回一个迭代器,不过这个迭代器时一个生成器对象。

举个例子:

from itertools import islice

def fib():
    a, b = 1, 1
    while True:
        yield a
        a, b = b, a + b

if __name__ == '__main__':
    fib_data = fib()
    print(list(islice(fib_data, 0, 10)))

可以看到,使用生成器后,代码简洁了很多!在上述代码中添加:

print(type(fib_data))
print(dir(fib_data))

可以看到函数返回的是一个generator对象,且对象实现了迭代器协议。

但是,使用生成器必须要注意的一点是:生成器只能遍历一次

什么时候用生成器呢?

生成器可以使用更少的中间变量来写流式代码, 相比于其它容器对象占用的内存和CPU资源更少一些。当需要一个将返回一个序列或在循环中执行的函数时,就可以使用生成器,因为当这些元素被传递到另一个函数中进行后续处理时,一次返回一个元素可以有效的提升整体性能,最重要的是,比迭代器简洁!

除此以外,生成器还有两个很棒的用处:

  1. 实现with语句的上下文管理器协议
  2. 实现协程

什么是生成器表达式?

列表推导式,大家应该都用到,但是由于内存的限制,列表的容量是有限的,如果要创建一个有几百万个元素的列表,会占用很多的储存空间,当我们只需要访问几个元素时,其它元素占用的空间就白白浪费了。

这种时候你可以用生成器表达式啊,生成式表达式是一种实现生成器的便捷方式,将列表推导式的中括号替换为圆括号,生成器表达式是一种边循环边计算,使得列表的元素可以在循环过程中一个个的推算出来,不需要创建完整的列表,从而节省了大量的空间。

In [1]: a = (item for item in range(10))

In [2]: type(a)
Out[2]: generator

In [3]: next(a)
Out[3]: 0

In [4]: next(a)
Out[4]: 1

以上。

代码可参考:my github

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-12-21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档