专栏首页Python空间面试必备 | 带你彻底搞懂 Python 生成器。

面试必备 | 带你彻底搞懂 Python 生成器。

本文字数:2281 字

阅读本文大概需要:6 分钟

写在之前

Python 的高级语言特性一直是我们学习 Python 的一个难点,大部分人并没有做到熟练的掌握,甚至去学习它都感觉很困难,「生成器」作为其中甚是有用的特性之一,更是如此。

因为在其它的主流语言(C/C++/JAVA)中并没有生成器的概念,加之其具有一定的难度,学习起来花费的时间成本较大,很多人自我安慰式的视其为“鸡肋”,然后果断放弃如此有用的一个高级语言特性,实在是一件很惋惜的事情。

其实不光是对于「生成器」而言,对于其它的高级语言特性还是建议大家要花点时间去搞懂的,不说其它,这些东西作为面试中常考的内容也应该引起你的重视,毕竟公司不是傻瓜,没有用的东西干嘛要考你?

接下来就让我们来一起学习「生成器」,我尽量用大家都听的懂的话,层层递进的讲解,保证大家都能看懂,前提是要有耐心,文章较长,建议先收藏再看。

答应我,一定要有耐心。

迭代器

在这说「迭代器」的原因是「生成器」自动实现了「迭代器协议」,所谓协议,就是一种约定。为了更好的理解生成器,我们需要简单知道一下「迭代器协议」到底是个什么东西。其实只需要满足两个两个条件:1.实现 __iter__ 方法;2.对象实现 next() 方法,要么返回迭代中的下一项,要么就是以 StopIteration 异常终止迭代。

对象就是「可迭代对象」,即实现了迭代器协议的对象,它实现了迭代器协议。其实像是 Python 中 for 循环,sum 函数等等就是使用迭代器协议访问对象。

你可能看着有点懵,怎么又是「迭代」又是「迭代器」又是「可迭代对象」的,这对大家来说是很抽象的概念,但是不用怕,我在很久之前的文章中,已经很详细的介绍过这俩哥们,你只需要点击下面的链接去看就好了,这也是面试中常见的问题哦:

零基础学习 Python 之初识迭代

Python 拓展之迭代器

生成器

如果你理解了上一节的内容,那么恭喜你,接下来学习「生成器」就会简单很多。Python 使用生成器对「延迟操作」提供了支持,所谓「延迟操作」就是在需要它的时候才产生结果,而不是说立即产生结果。

首先我们先来看一个入门级别的版本,你只需要点击下面的链接即可:

零基础学习 Python 之初识生成器

接下来讲的相当于是上面文章的一个延伸和再拓展。

Python 其实有两种不同的方法来提供生成器,一种是函数形式,另一种是表达式形式,说全一点儿就是「生成器函数」和「生成器表达式」。

1.生成器函数

「生成器函数」和普通的函数定义类似。区别在于普通函数使用 return 返回结果,生成器函数是用 yield 返回结果。

yield 的作用是在调用的时候返回相应的值,一次返回一个结果,在每个结果中间挂起函数的状态(即暂停执行),下一次执行是从上次暂停的位置开始,继续向下执行。

下面我们来做一道题,要求写出「将一个全是整数的列表进行操作后只保留奇数」。相信大多数人都能很快的写出下面这样的函数:

def get_odd(lst):
    res = []
    for i in lst:
        if i % 2:
            res.append(i)
    return res

def main():
    lst = range(10)
    for i in get_odd(lst):
        print(i)

if __name__ == '__main__':
    main()

上面这个没什么难度,既然我们学了「生成器」,我在前面还这么舔它,是不是我们该用生成器来做一下这道题?看看用生成器来做同样的功能,到底有什么不同:

def get_odd(lst):
    for i in lst:
        if i % 2:
            yield i

def main():
    lst = range(10)
    for i in get_odd(lst):
        print(i)

if __name__ == '__main__':
    main()

对比一下这个功能的两种做法,使用「生成器」以后,代码变的行数更少了(省去了对 res 的操作,不用把结果存在 res 里),代码整体看起来更清晰了(一看就知道干嘛的,不用一上来去想 res 是个什么鬼,append 进去的是个什么玩意儿)。

2.生成器表达式

「生成器表达式」和列表推导式类似。区别在于使用列表推导,一次会产生所有的结果,而用「生成器表达式」则不会这样,它是按需产生。

列表推导式的写法如下:

>>> res = [x for x in range(5)]
>>> res
[0, 1, 2, 3, 4]

生成器表达式就是将上面的 [] 变成 () 即可:

>>> res = (x for x in range(5))
>>> res
<generator object <genexpr> at 0x109d9f570>
>>> next(res)
0
>>> next(res)
1
>>> next(res)
2
>>> next(res)
3

我们也顺便简单的看一下「生成器」的优势在「生成器表达式」中是怎么体现的。如果我们想对一系列整数求和,直接用生成器可以写成下面这样:

>>> sum((x for x in range(5)))
10

当然为了方便起见,也可以省略圆括号,即写成下面这样:

>>> sum(x for x in range(5))
10

但是如果你用常规的写法去写,就会写成下面这样:

>>> sum([x for x in range(5)])
10

上面的代码先构造了一个列表,然后再用 sum 函数求和,多了一步,天差地别,光在时间效率上,就已经输掉了裤子。

所以综合上面文章所讲,「生成器」光在明面上的优点就有好几个:代码行数更少;代码更易读;时效更高...

所以,你还敢视它为“鸡肋”吗?

本文分享自微信公众号 - Python空间(Devtogether),作者:Rocky0429

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-02-22

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 零基础学习 Python 之初识生成器

    昨天的文章中(Python 拓展之迭代器)我们学了「迭代器」,今天我们就来学学另一个 -- 「生成器」。如果不出意外的话,「生成器」这个部分是我们在“类”里面的...

    Rocky0429
  • 听说你还不会将数据存入文件?

    在前面的文章中,我们学过用 Python 如何读写文件。程序执行结果,就是产生一些数据,一般情况下,这些数据要保存到磁盘中,最简单的方法就是写入到某个文件。但是...

    Rocky0429
  • 零基础学习 Python 之与函数的初次相见

    大家好,这里是零基础学习 Python 系列,在这里我将从最基本的Python 写起,然后再慢慢涉及到高阶以及具体应用方面。我是完全自学的 Python,所以很...

    Rocky0429
  • 敲黑板嘞!一文彻底搞懂 Python 生成器!

    Python 的高级语言特性一直是我们学习 Python 的一个难点,大部分人并没有做到熟练的掌握,甚至去学习它都感觉很困难,「生成器」作为其中甚是有用的特性之...

    小小詹同学
  • 面试必备 | 带你彻底搞懂 Python 生成器。

    Python 的高级语言特性一直是我们学习 Python 的一个难点,大部分人并没有做到熟练的掌握,甚至去学习它都感觉很困难,「生成器」作为其中甚是有用的特性之...

    不羁的程序员小王
  • 技术 | Python从零开始系列连载(十九)

    但它的特点就是下次使用next(a)时,接着上次的断点继续运行,直到下一个yield

    灯塔大数据
  • Python进阶系列连载(5)——生成器(上)

    作者:王大伟 Python爱好者社区唯一小编 博客:https://ask.hellobi.com/blog/wangdawei 生成器 还记得在迭代器里我们...

    企鹅号小编
  • Python生成器、推导式之前襟后裾

    生成器 函数体内有yield选项的就是生成器,生成器的本质是迭代器,由于函数结构和生成器结构类似,可以通过调用来判断是函数还是生成器,如下:

    用户2398817
  • Python--高级特性

    •列表生成式(列表生成式是Python 内置的非常简单却强大的可以用来创建 list的生成式), 当生成时元素即打印, 会占用内存;

    用户2398817
  • PHP中性能优化之生成器

    问题背景 PHP生成器是PHP的5.5.0版本引入的功能,生成器实际上就是简单的迭代器。生成器会根据需求计算产出迭代的值,而标准的PHP迭代器经常在内存中执行迭...

    企鹅号小编

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动