通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器(Generator)。

要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

>>> g=(x*x for x in range(10))
>>> g
<generator object <genexpr> at 0x05E42DF0>

创建Lg的区别仅在于最外层的[]()L是一个list,而g是一个generator。

我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?

如果要一个一个打印出来,可以通过generator的next()方法:

我们讲过,generator保存的是算法,每次调用next(),就计算出下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

当然,上面这种不断调用next()方法实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象:

>>> for n in g:
print(n) 1
4
9
16
25
36
49
64
81

所以,我们创建了一个generator后,基本上永远不会调用next()方法,而是通过for循环来迭代它。

generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

def fib(max):
n,a,b=0,0,1
while n<max:
print(b)
a,b=b,a+b
n=n+1

上面的函数可以输出斐波那契数列的前N个数:

>>> fib(6)
1
1
2
3
5
8

仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。

也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print b改为yield b就可以了:

def fib(max):
n,a,b=0,0,1
while n<max:
yield b
a,b=b,a+b
n=n+1

这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator

>>> fib(5)
<generator object fib at 0x06282970>

这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

举个简单的例子,定义一个generator,依次返回数字1,3,5:

>>> def odd():
... print 'step 1'
... yield 1
... print 'step 2'
... yield 3
... print 'step 3'
... yield 5
...
>>> o = odd()
>>> o.next()
step 1
1
>>> o.next()
step 2
3
>>> o.next()
step 3
5
>>> o.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

可以看到,odd不是普通函数,而是generator,在执行过程中,遇到yield就中断,下次又继续执行。执行3次yield后,已经没有yield可以执行了,所以,第4次调用next()就报错。

回到fib的例子,我们在循环过程中不断调用yield,就会不断中断。当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。

同样的,把函数改成generator后,我们基本上从来不会用next()来调用它,而是直接使用for循环来迭代:

>>> for n in fib(6):
... print n
...
1
1
2
3
5
8

小结

generator是非常强大的工具,在Python中,可以简单地把列表生成式改成generator,也可以通过函数实现复杂逻辑的generator。

要理解generator的工作原理,它是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。

python学习之路(14)的更多相关文章

  1. Python学习之路14☞多线程与多进程

    一 进程与线程的概念 1.1 进程 进程定义: 进程就是一个程序在一个数据集上的一次动态执行过程.进程一般由程序.数据集.进程控制块三部分组成.我们编写的程序用来描述进程要完成哪些功能以及如何完成:数 ...

  2. python学习之路-day2-pyth基础2

    一.        模块初识 Python的强大之处在于他有非常丰富和强大的标准库和第三方库,第三方库存放位置:site-packages sys模块简介 导入模块 import sys 3 sys模 ...

  3. Python学习之路-Day2-Python基础3

    Python学习之路第三天 学习内容: 1.文件操作 2.字符转编码操作 3.函数介绍 4.递归 5.函数式编程 1.文件操作 打印到屏幕 最简单的输出方法是用print语句,你可以给它传递零个或多个 ...

  4. Python学习之路【第一篇】-Python简介和基础入门

    1.Python简介 1.1 Python是什么 相信混迹IT界的很多朋友都知道,Python是近年来最火的一个热点,没有之一.从性质上来讲它和我们熟知的C.java.php等没有什么本质的区别,也是 ...

  5. python学习之路------你想要的都在这里了

    python学习之路------你想要的都在这里了 (根据自己的学习进度后期不断更新哟!!!) 一.python基础 1.python基础--python基本知识.七大数据类型等 2.python基础 ...

  6. Python学习之路-Day2-Python基础2

    Python学习之路第二天 学习内容: 1.模块初识 2.pyc是什么 3.python数据类型 4.数据运算 5.bytes/str之别 6.列表 7.元组 8.字典 9.字符串常用操作 1.模块初 ...

  7. Python学习之路-Day1-Python基础

    学习python的过程: 在茫茫的编程语言中我选择了python,因为感觉python很强大,能用到很多领域.我自己也学过一些编程语言,比如:C,java,php,html,css等.但是我感觉自己都 ...

  8. python学习之路网络编程篇(第四篇)

    python学习之路网络编程篇(第四篇) 内容待补充

  9. python 学习之路开始了

    python 学习之路开始了.....记录点点滴滴....

  10. python学习之路,2018.8.9

    python学习之路,2018.8.9, 学习是一个长期坚持的过程,加油吧,少年!

随机推荐

  1. ATM机小程序

    用规范化项目录的格式模拟一个ATM系统. 项目功能: 登录(可支持多个账户(非同时)登录) 注册 查看余额 存钱 转账(给其他用户转钱) 查看账户流水 退出 提供的思路:ATM直译就是取款机,但是咱们 ...

  2. python第三方库-图像处理库pillow

    python图像处理库pillow 安装 pip install pillow 使用 导入 from PIL import pillow 读取图像 picture = Image.open('test ...

  3. Ruby Rails正式学习:Ruby on Rails 做个演示项目吧,逐渐完善

    项目开始 一. 新建Rails项目 1. 修改一下Gemfile文件(简单修改一下) source 'https://rubygems.org' git_source(:github) { |repo ...

  4. python flask解决上传下载的问题

    记录瞬间 最近为了解决一些新的需求,简单介入了flask对文件的上传和下载的方法,并分别使用python和curl模拟发送 代码: #! /usr/bin/env python3 # coding:u ...

  5. @RequestMapping-限定参数映射

    限定参数映射 测试:

  6. JavaScript制作九九乘法表

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  7. iview表单验证之正则验证、函数验证

    iview表单验证之正则 正则验证: 代码: loginRules: { stringLength: [ { required: true, message: '该字段不能为空', trigger: ...

  8. java接口自动化测试小dome

    GitHub地址:https://github.com/leonInShanghai/InterfaceAutomation 这个dome 请求 https://www.v2ex.com/api/no ...

  9. 百度的echarts报表数据直接显示

    最近在使用百度的echarts开发,在使用过程中,遇到点需求,就是希望显示的数据直接在图标上显示,而不是鼠标滑动以后才显示,于是百度搜了下相关的文章正好找到了,然后使用了这个方法是可以用的,所以这里记 ...

  10. insightface作者提供数据训练解读

    1.下载源码: 开源代码地址:https://github.com/deepinsight/insightface 2.查看作者项目训练要求 (1)训练数据 训练数据使用作者提供并制作好的数据,如下图 ...