ql的python学习之路-day10
前言:本节主要讲解迭代器和生成器
迭代器&生成器
一、生成器(generator)
循环占用大部分的容量内存,如果只需要循环前面的几个结果那怎么样做呢,在python中有一种一边循环一边计算的机制,称为生成器:generator,就能解决这个问题。
生成器只有在调用的时候才会产生相应的数据,用__next()__方法调用(2.7版本里是next()),生成器只能记录当前的位置,不能后退也不能记录以后的数据。
实例:斐波那契数列中的生成器
- #!/usr/bin/env python
- # -*- coding:utf-8 -*-
- # Author:qinjiaxi
- def fib(max):
- n, a, b = 0, 0, 1#初始化
- while n < max:#循环
- yield b
- #print(b)#打印b
- a, b = b, a + b
- n += 1
- return "done"#异常的时候打印的消息
- #抓异常
- g = fib(6)
- while True:
- try:
- x = next(g)
- print("g:", x)
- except StopIteration as e:
- print("Generator return value:", e.value)
- break
- #调用生成器
- f = fib(10)
- print(f)#打印生成器对象的内存地址
- print(next(f))#取第一个值
- print(f.__next__())#取第二个值
- print(next(f))#取第三个值
- print("---start loop---")
- for i in f:#循环取剩下的数据
- print(i)
- #注:当用next()方法调用次数超过设定值时,会产生异常
- #理解其中的a, b = b, a + b
- t = (b, a + b)#实际有个临时变量t,t是一个元组
- a = t[0]
- b = t[1]
- #t不会显式的出现在代码中
生成器实际工作中的应用:协程(单线程并行处理),异步io处理
yeild作用是保存当前状态并返回,无返回值(返回值是None)
next方法调用yield,send方法调用yield并给yield传值,yield后面加上一个变量,可以返回变量
协程1源码:
- #!/user/bin/env python
- #-*-coding:utf-8 -*-
- #Author: qinjiaxi
- import time
- def consumer(name):
- print("%s准备吃包子了" % name)
- while True:
- baozi = yield
- print("包子[%s]被%s吃了" % (baozi, name))
- c = consumer('ql')
- #next(c)#停在yield位置(中断,返回迭代值)
- #c.__next__()#从yield下一句开始执行,由于默认没有给yield传递参数所以返回的是None,执行完后又回到yield这一行
- #c.__next__()
- #c.send("韭菜馅的")#send方法可以调用yield并且给yield传送参数
- def producer(name):
- c = consumer('A')
- c1 = consumer('B')
- c.__next__()#A准备吃包子了
- c1.__next__()#B准备吃包子了
- print("%s开始做包子了" % name)
- for i in range(10):
- time.sleep(1)
- print("做了一个包子分两半")
- c.send(i)#传递i到A的yield,给A的yield赋值
- c1.send(i)#传递i到B的yield,给B的yield赋值
- producer('qinlang')
协程2源码:
- #!/user/bin/env python
- #-*-coding:utf-8 -*-
- #Author: qinjiaxi
- import time
- def consumer():
- r = ''#初始化r
- while True:
- n = yield r#将值传给n,然后执行下一句,碰到r变量再返还r给producer函数
- print("[consumer] is consuming %s " % n)
- r = '200 is ok'
- def producer(c):
- c.send(None)
- n = 0
- while n < 5:
- n = n + 1
- time.sleep(1)
- print("[producer] is producting %s" % n)
- r = c.send(n)
- print("[producer] cousumer return %s" % r)
- # for i in range(6):
- # time.sleep(1)
- # print('[producer] is producing %s ' % i)
- # r = c.send(i)#传n值给生成器yield
- # print('[producer] consumer return %s' % r)
- c.close()#关闭生成器
- c = consumer()
- producer(c)
结论:
一个带有yield的函数就是一个generator,它和普通函数不一样,生成器generator看起来像函数,其实不会执行任何函数代码,直到对其调用next()方法(在for循环中会自动调用next()方法)才会执行。虽然执行仍然像函数一样执行,其实当执行到yield时候就会中断并返回一个迭代值,当再次调用next()方法时从yield下一句开始执行。看起来就好像一个函数在正常执行的时候被yield中断了数次,每次中断都会通过yield返回迭代值。
二、迭代器(Iterator)
我们知道能直接作用于for循环的数据类型有以下几种:
一类是集合数据类型,如list、tuple、str、set、dict
一类是generator,包括生成器和带yield的generator function
*这些可以直接作用于for循环的对象统称为可迭代对象:Iterable
可以使用isinstance()来判断一个对象是否是iterable对象:
- >>> from collections import Iterable
- >>> isinstance([], Iterable)
- True
- >>> isinstance('abc', Iterable)
- True
- >>> isinstance({}, Iterable)
- True
- >>> isinstance((i for i in range(10)), Iterable)
- True
- >>> isinstance(100, Iterable)
- False
生成器不但可以作用于for循环,还可以被next()函数不断的调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值。
*可以被next()函数调用并且不断返回下一个值的对象称为迭代器:Iterator
可以使用isinstance()来判断一个对象是否是interator对象:
- >>> from collections import Iterator
- >>> isinstance([], Iterator)
- False
- >>> isinstance({}, Iterator)
- False
- >>> isinstance((i for i in range(10)), Iterator)
- True
由上可知生成器都是Iterator对象,但list、dict、str虽然是Iterable但不是Iterator。
把list、dict、str等Iterable变成Iterator可以使用iter()函数:
- >>> isinstance(iter([]), Iterator)
- True
- >>> isinstance(iter('abc'), Iterator)
- True
- >>> isinstance(iter({}), Iterator)
- True
为什么list、dict、str等数据不是Iterator?
因为python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断的返回下一个数据,直到没有数据时抛出StopIteration错误。可以把数据流看做是一个有序序列,但是我们提前并不知道序列的长度,只有通过next()函数按需继续下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据的时候才计算。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。但是list是永远不可能村粗全体自然数的。
小结:
凡是可作用于for循环的对象都是Iterable类型(可迭代类型);
凡是可以作用于next()函数的对象都是Iterator类型(迭代器类型),它们表示一个惰性的计算序列;
集合数据类型例如list、dict、str等都是Iterable(可迭代对象)但不是Iterator(迭代器),可以通过iter()函数获得一个迭代对象。
Python的for循环的本质就是不断的通过调用next()函数实现的。
python3.0中range(10)其实是一个迭代器
python2.x中xrange(10)是迭代器
ql的python学习之路-day10的更多相关文章
- ql的python学习之路-day15
前言:本节主要讲解的是文件路径 在实际的软件开发中会设计一个项目的文件目录,按照执行包bin.配置包config.核心包core等来设计,在执行包里面要运行核心包里的主程序mian,由于不在同一级的目 ...
- ql的python学习之路-day14
前言:本节主要学习时间模块time.datetime python中的几种时间表示:1)时间戳 2)格式化的字符串时间 3)struct_time元组格式的时间 time.datetime模块源码: ...
- ql的python学习之路-day13
前言:本节主要学习模块 一.模块的定义 模块:本质是.py结尾的python文件(文件名:test.py,对应的模块是:test),用来从逻辑上组织python代码(变量.函数.类.逻辑,本质是实现一 ...
- ql的python学习之路-day12
前言:这一节主要学习json和pickle 背景: 相信大家在日常生活中都有接触大型的网络游戏,打游戏的时候都是自己在电脑上操作,自己刷怪升级:当然也会碰到中午去吃饭然后挂机的情况,让电脑自动的刷怪, ...
- ql的python学习之路-day11
前言:本节主要学习python内置的方法 #!/usr/bin/env python # -*- coding:utf-8 -*- # Author:qinjiaxi from collections ...
- ql的python学习之路-day9
前言:本节主要学习装饰器 一.装饰器 定义:本质上是个函数,用来装饰其他函数:(就是为其他函数添加附加功能) 原则:1.不能修改被装饰的函数的源代码 2.不能修改被装饰的函数的调用方式 以上两点可以总 ...
- ql的python学习之路-day8
前言:本节主要学习的是函数的全局变量和局部变量以及递归 一.全局变量和局部变量 定义在函数外并且在函数头部的变量,叫做全局变量,全局变量在整个代码中都生效. 局部变量只在函数里生效,这个函数就叫做这个 ...
- ql的python学习之路-day7
函数与函数式编程 一.编程模式分为三种: 1.面向对象编程:类----->关键字class 2.面向过程编程:过程----->关键字def,没有return 3.函数式编程:函数----- ...
- ql的python学习之路-day6
字节编码: 这一节主要学习的是各种编码模式的相互转换,另外插两句话,今天的心情不是特别好,又没控制好自己的情绪,以后要心存阳光,好好的对待生活和身边的人. 废话不多说了直接贴码: #!/usr/bin ...
随机推荐
- Java 多线程实现方式一:继承Thread类
java 通过继承Thread类实现多线程很多简单: 只需要重写run方法即可. 比如我们分三个线程去京东下载三张图片: 1.先写个下载类: 注意导入CommonsIO 包 public class ...
- 借助leetcode题目来了解BFS和DFS
广度优先和深度优先搜索 前言 看着这两个搜索的前提的是读者具备图这一数据结构的基本知识,这些可以直接百度一波就了解了.图也像树一样,遍历具有很多的学问在里面,下面我将借用leetcode的题目讲解一下 ...
- 关于flex弹性布局
http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html
- 设定程序随windows启动
Boot Trigger Example (C++) /******************************************************************** Thi ...
- Spring5参考指南:容器扩展
文章目录 BeanPostProcessor自定义bean BeanFactoryPostProcessor自定义配置元数据 使用FactoryBean自定义实例化逻辑 Spring提供了一系列的接口 ...
- 【JAVA基础】05 Java语言基础:数组
1. 数组概述和定义格式说明 为什么要有数组(容器) 为了存储同种数据类型的多个值 数组概念 数组是存储同一种数据类型多个元素的集合.也可以看成是一个容器. 数组既可以存储基本数据类型,也可以存储引用 ...
- 标准库模块time,datetime
在Python中,通常有这几种方式来表示时间: 1)时间戳 2)格式化的时间字符串 3)元组(struct_time)共九个元素. 由于Python的time模块实现主要调用C库,所以各个平台可能有所 ...
- 20060518: Alert!
Alert Received, Shrink My Blog! 转载于:https://www.cnblogs.com/yidinghe/archive/2006/05/18/403089.html
- eggjs解决跨域问题
Egg.js 是什么? Egg.js 为企业级框架和应用而生,我们希望由 Egg.js 孕育出更多上层框架,帮助开发团队和开发人员降低开发和维护成本. Egg.js特性 提供基于 Egg 定制上层框架 ...
- 2019年2月5日训练日记关于int字节数,long int 字节数的讨论
今天做到了个非常有意思的题目,是关于int最大最小值.用sizeof(int)查寻,返回四个字节,4个字节计算应该是4*8=32位,其中一位为符号位,且最高为不能为2所以应该减一,2^31-1=214 ...