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

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

要创建一个generator,有很多种方法。

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

1. 简单的列表操作:

 >>> list1 = [x*x for x in range()]
>>> list1
[, , , , , , , , , ]
>>> list2 = [*x for x in range()]
>>> list2
[, , , , , , , , , , , ]
>>>

2. 生成器操作:

 >>> list3 = (x*x for x in range())
>>> list3
<generator object <genexpr> at 0x7f302fdb6cd0>
>>> list1
[, , , , , , , , , ]
>>> list2
[, , , , , , , , , , , ]
>>>

如代码所示,list1和list2是一个列表,而list3是一个generator,在任意时刻我们可以随便打印出list1和list2的列表元素,但是我们怎么才可以打印出list3的元素呢?,在这里generator提供一个打印自身元素的函数,next()。

 >>> list3
<generator object <genexpr> at 0x7f302fdb6cd0>
>>> list3.next() >>> list3.next() >>> list3.next() >>> list3.next() >>> list3.next() >>> list3.next() >>> list3.next() >>> list3.next() >>> list3.next() >>> list3.next() >>> list3.next()
Traceback (most recent call last):
File "<stdin>", line , in <module>
StopIteration
>>>

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

使用next方法虽然可以计算出生成器的值,但是,实在是太不人性化了,在此,还有没有更好的方法来输出生成器的值呢?方法肯定是有的,那就是采用for迭代输出:

 >>> list4 = (x*x for x in range())
>>> list3
<generator object <genexpr> at 0x7f302fdb6cd0>
>>> for n in list4:
... print n
... >>>

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

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

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

1, 1, 2, 3, 5, 8, 13, 21, 34, ...

斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

 >>>
>>> def fibla(max):
... n,a,b = ,,
... while n < max:
... print b
... a,b = b,a+b
... n = n +
...
>>> fibla() >>>

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

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

 >>> def fibla(max):
... n,a,b = ,,
... while n < max:
... print b
... a,b = b,a+b
... n = n +
...
>>> fibla() #上下对比
>>> def fibla(max):
... n,a,b = ,,
... while n < max:
... yield b
... a,b = b,a+b
... n = n +
...
>>> fibla()
<generator object fibla at 0x7f302fd5ca00>
>>>

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

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

 >>> def fibla(max):
... n,a,b = ,,
... while n < max:
... yield b
... a,b = b,a+b
... n = n +
...
>>> fibla()
<generator object fibla at 0x7f302fd5ca00>
>>> for x in fibla():
... print x
... >>>

python学习之---生成器的更多相关文章

  1. python学习之生成器

    4.6 生成器Generrator ​ 生成器本质就是迭代器.python社区生成器与迭代器是一种. ​ 生成器与迭代器的唯一区别:生成器是我们自己用python代码构建的 4.6.1生成器初识 py ...

  2. Python学习二(生成器和八皇后算法)

    看书看到迭代器和生成器了,一般的使用是没什么问题的,不过很多时候并不能用的很习惯 书中例举了经典的八皇后问题,作为一个程序员怎么能够放过做题的机会呢,于是乎先自己来一遍,于是有了下面这个ugly的代码 ...

  3. Python学习笔记 - 生成器generator

    #!/usr/bin/env python3 # -*- coding: utf-8 -*- # generator 生成器 L = [x * x for x in range(10)] print( ...

  4. Python学习——迭代器&生成器&装饰器

    一.迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素.迭代器仅 ...

  5. python学习-39 生成器总结

    总结 1.语法上和函数类似:生成器函数和常规函数几乎是一样的.它们都是使用def语句进行定义,差别在于,生成器使用yield语句返回一个值,常规函数使用return语句返回一个值. 2.自动实现迭代器 ...

  6. python学习之- 生成器/迭代器

    列表生成式写法: [ i*2 for i in range(10) ]也可以带函数 [ fun(i) for i in range(10) ] 生成器:一边循环一边计算的机制称为生成器.在常用函数中, ...

  7. Python学习---装饰器/迭代器/生成器的学习【all】

    Python学习---装饰器的学习1210 Python学习---生成器的学习1210 Python学习---迭代器学习1210

  8. Python学习笔记之生成器、迭代器和装饰器

    这篇文章主要介绍 Python 中几个常用的高级特性,用好这几个特性可以让自己的代码更加 Pythonnic 哦 1.生成器 什么是生成器呢?简单来说,在 Python 中一边循环一边计算的机制称为 ...

  9. python学习10—迭代器、三元表达式与生成器

    python学习10—迭代器.三元表达式与生成器 1. 迭代器协议 定义:对象必须提供一个next方法,执行该方法或者返回迭代中的下一项,或者返回一个StopIteration异常,以终止迭代(只能往 ...

随机推荐

  1. python调用smtplib模块发送邮件

    #!/usr/bin/env python #coding: utf-8 import smtplib from email.mime.text import MIMEText from email. ...

  2. 在某些情况下明明添加了引用,为何VS还报错"XXX"不存在类型或命名空间(是否缺少程序集引用)

    程序主结构:两个程序集DLL,一个OpticalAlarm(主程序),一个OpticalAlarm.Common 问题描述:搭建程序框架时,使用了log4net进行日志处理,在OpticalAlarm ...

  3. Magento 的程序架构与流程

    以下是分别详细解读分析程序的各层次源码: MAGENTO_ROOT: //入口文件 /index.php -----–| 1.判断php版本是否大于5.22.引入Magento主要的中心类/app/M ...

  4. Apache 配置多端口 多虚拟主机 局域网访问

    \wamp\bin\apache\Apache2.4.4\conf\extra\httpd-vhosts.conf 修改如下 NameVirtualHost *:80          Documen ...

  5. web.config详解(配置文件节点说明)

    转载:http://www.zzzj.com/html/20081110/67614.html web.config文件是一个XML文件,它的根结点是<configuration>,在&l ...

  6. JDK版本过高,导致Eclipse报错

    1.JDK版本如果比较高,而使用的eclipse版本比较低,导致在eclispe中不能识别而报错.   2.点击Attach Source添加rt.jar后,又出现如下错误 3.这样的错误就是由于ec ...

  7. Html+CSS命名规范:

     Html+CSS命名规范: 1.样式命名: 2.样式文件命名:

  8. java.lang.NoSuchMethodError: org.apache.neethi.Policy.normalize(Z)Lorg/apache/neethi/PolicyComponent

    记录一个org.apache.neethi包的异常 java.lang.NoSuchMethodError: org.apache.neethi.Policy.normalize(Z)Lorg/apa ...

  9. UVA 11584 Paritioning by Palindromes(动态规划 回文)

    题目大意:输入一个由小写字母组成的字符串,你的任务是把它划分成尽量少的回文串.比如racecar本身就是回文串:fastcar只能分成7个单字母的回文串:aaadbccb最少可分成3个回文串:aaa. ...

  10. 鼠标操作[OpenCV 笔记10]

    ) winname 窗口名字 onMouse 指定窗口每次鼠标事件发生的时候,被调用的函数指针.函数的原型应为void Foo(int event, int x, int y, int flags, ...