python基础6 迭代器 生成器
迭代器
可迭代的或迭代对象
可迭代的:内部含有__iter__方法的数据类型叫可迭代的,也叫迭代对象 , range是一个迭代对象,内部含有iter()方法。为什么可迭代对象能被for 循环,因为可迭代对象含有iter方法,只要函数iter方法的对象就可以被for循环。这也是可迭代协议。
运用dir()方法来测试一个数据类型是不是可迭代的的。如果含有iter的,就是可迭代对象、
迭代器协议
迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前退)。
迭代器:可以被next()
函数调用并不断返回下一个值的对象称为迭代器,迭代器是一个实现了迭代器协议的对象。也可以这样说包含next方法的可迭代对象叫迭代器
迭代器和列表的区别?
区别在于节省内存和惰性运算
如果我有一个列表中有500个数据,那么这个列表就非常占用内存,如果把列表变为迭代器,就占用很少的内存,为什么会占用内存少呢,因为迭代器只记录当前这元素和下一个元素,当你找我要的时候我才在内存中生成数据,不找我要,就不生成数据,也就不占用内存,这就是迭代器的惰性运算。
如何区分迭代器和可迭代对象?这个在我们时间长了后会混淆。
可迭代对象最简单的定义:可以使用for in 语句进行循环的对象。比如字符串、列表、元组、字典以及迭代器、生成器都是可迭代对象。而迭代器是可以使用next()进行回调的对象,迭代器比可迭代对象多一个__next__方法。可迭代对象和迭代器的联系是:可以对迭代对象使用iter()方法来生成迭代器。
判断一个变量是不是迭代器或者可迭代对象?
from collections import Iterator
from collections import Iterable
print(isinstance([1,2,3,4],Iterable))
str_iter="abc".__iter__()
print(isinstance(str_iter,Iterator))
结果:
True
True
注意!!!文件和enumerate含有next和iter方法所以是迭代器,例如:
enumerate范例:
from collections import Iterator
l=[1,3,4]
print(isinstance(enumerate(l),Iterator))
结果:
True
文件范例:
with open("产品",encoding="utf-8") as f:
print("__next__" in dir(f))
结果:
True
迭代器的特点:
1.节省内存
2.惰性运算(什么时候用到,什么时候运行)
3.从前到后一次取值,过程不可逆,不可重复。
如果把迭代对象转变为迭代器?
可迭代对象调用自己的__iter__().方法就会返回一个迭代器
迭代器=iter(迭代对象) 注意:iter(迭代对象)=迭代对象.__iter__() next 和它的用法一样
迭代器的方法:
1.__next__方法:返回迭代器的下一个 元素。
2.__iter__方法:返回迭代器对象本身。
l=["ha","hei","he"]
ret=l.__iter__() #这个步骤生成迭代器,ret就称为了一个迭代器。 print(ret.__next__())
print(ret.__next__())
迭代器比可迭代对象多一个__next__方法
包含__next__方法的可迭代对象就是迭代器
for循环原理
1.先判断对象是不是可迭代对象,如果不是直接报错,如果是的话,调用__iter__()返回一个迭代器。
2.然后不断的调用生成的迭代器的next()方法,每次返回一个值。
3.迭代到最后,没有更多元素了,就抛出异常 StopIteration,这个异常 python 自己会处理,不会暴露给开发者
这也就是用for循环取值节省内存的原因。
模拟for循环,解释for循环的内部原理。
不加try ....except 的情况下:
范例一:
l=[1,2,3,4,5]
ite=l.__iter__()
while True:
print(ite.__next__())
结果:
1
2
3
4
5 StopIteration 出现这种原因是while 循环不可以自动停止,然而迭代器从前到后一次取值,
过程不可逆,不可重复,所以就出现了这种情况。
如何避免这种错误?
范例二:
l=[1,2,3,4,5]
ite=l.__iter__()
while True:
try:
print(ite.__next__())
except StopIteration:
break
结果:
1
2
3
4
5
总结:for循环是让我们更简单的使用迭代器,用迭代器取值不需要关心索引或者key.
作者:酱油哥
链接:https://www.zhihu.com/question/20829330/answer/286837159
生成器
为什么要有生成器?
迭代器是从集合中取数据,而生成器是创造数据,这点从斐波那契中就可以看出区别来了,我们知道斐波那契数是无穷的,在集合中放不下,那么我们如何生成所有的斐波那契呢,这就用到了生成器
例如
def f():
a=0
b=1
while True:
yield a
yield b
a = b + a
b=b+a for i in f():
print(i)
含有有yield 的函数被称之为生成器(generator)函数。
生成器函数执行后会得到一个生成器(generator)
生成器本质:生成器是迭代器,它包含一切迭代器的方法。
生成器的作用是
- 延迟计算一次只产生一个数据项.
- 增加代码的可阅读性
yield关键字
yield的作用:
- 记住上次执行的状态
- 自动切换到不同任务
- 1次只返回一个结果, 把返回值传递给next() 的调用方
调用生成器send方法传递数据时,必须先调用next(g)或者g.send(None)方法,执行到yield语句,等待接收数据。否则会报错。
def func():
a = yield 5 # send中的值先找到上次暂停的位置,然后把yield 5 替换成world 这里就变成了 a="world
print("a>>>", a)
yield 22 g = func()
num = g.__next__()
print("num>>>",num)
foo = g.send('world') # send相当于next(),但是他又和next又有不同,他可以传值给上次暂停的地方,但是send第一次不能先执行,必须先执行next()或者send(none)
print('foo>>', foo)
结果:
num>>> 5
a>>> world
foo>> 22
实现yield 的切换任务的例子,即实现协程的例子
import time
def consumer():
r = "开始吃包子了~"
while True:
x = yield r #r发给send的调用方,x 接收send的传的值
print("我正在吃包子%s"%(x))
r = "包子已经收到"
time.sleep(1) def producer(c):
p = c.__next__()
print(p)
n = 0
while n < 5:
n = n + 1
print("生产者生产包子%s" % n)
nn = c.send(n)
print("send****")
print("收到消费者的消息为%s"%nn)
c.close() con = consumer()
producer(con)
结果:
开始吃包子了~
生产者生产包子1
我正在吃包子1 send****
收到消费者的消息为包子已经收到
生产者生产包子2
我正在吃包子2 send****
收到消费者的消息为包子已经收到
生产者生产包子3
我正在吃包子3 send****
收到消费者的消息为包子已经收到
生产者生产包子4
我正在吃包子4 send****
收到消费者的消息为包子已经收到
生产者生产包子5
我正在吃包子5 send****
收到消费者的消息为包子已经收到
yield能在两个任务之间保存状态和切换,实现了并发的效果.,但是这种并发没有什么意义,只有遇到io阻塞时切换并发才有意义
yield from 关键字
yield from 是在python3.3中出现的新语法.
如果一个生成器需要另一个生成器的值时,传统的方法就是用for循环,yield from就可以带起for循环
yield from 的主要功能是打开双向通道,把最外层的调用方与最内层的子生成器连接起
来,这样二者可以直接发送和产出值,还可以直接传入异常,而不用在位于中间的协程中
添加大量处理异常的样板代码
传统方式 for循环
def generator1():
item = range(5)
for i in item:
yield i def generator2():
yield 'a'
yield 'b'
yield 'c'
for i in generator1():
yield i
yield 'd'
for i in generator2() :
print(i)
使用yield from 语法
def generator1():
item = range(5)
for i in item:
yield i def generator2():
yield 'a'
yield 'b'
yield 'c'
yield from generator1() #yield from iterable本质上等于 for item in iterable: yield item的缩写版
yield 'd'
for i in generator2() :
print(i)
结果:
a
b
c
0
1
2
3
4
d
一个题目:
a="AB"
b="CD"
想要生成: A B C D
方法一:
def func():
a="AB"
b="CD"
for i in a:
yield i for i in b :
yield i f=func()
for i in f:
print(i)
方法二
def func():
a="AB"
b="CD"
yield from a
yield from b
f=func()
for i in f:
print(i)
yield from 调用生成器
def htest():
i = 1
while i < 4:
n = yield i
print("nnn",n)
if i == 3:
return 100
i += 1 def itest():
val = yield from htest() #调用生成器接收,yield from可以接收return的返回值
print("val>>>",val) t = itest()
t.send(None)
j = 0
while j < 3:
j += 1
try:
print('j',j)
t.send(j) #当t.send(3)时,htest函数早已经return了结束了
except StopIteration as e:
print('异常了')
j 1
nnn 1
j 2
nnn 2
j 3
nnn 3
val>>> 100
异常了
创建生成器的两种方法
1.生成器函数。常规函数定义,但是使用yield语句而不是return语句返回结果,yield返回值并不会终止程序的运行,一次只返回一个结果,在每个结果中间它会记住函数状态,以便下次从它离开的地方开始。
2.生成器表达式:
要介绍生成器表达式前,要先介绍列表生成式,即列表推导式,说白了就是如何生成一个列表
常规的写法 egg_list=[]
for i in range(10):
egg_list.append('鸡蛋%s' %i) 如果用列表推导式可以这么写 语法规则: for 左边是列表 中要存放的结果,for 右边是生成这个列表所需的条件. ret=['鸡蛋%s'%i for i in range(10)]
print (ret)
优点:方便,改变了编程习惯,可称之为声明式编程
结果:
['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']
#1、把列表推导式的[]换成()就是生成器表达式 #2、示例:生一筐鸡蛋变成给你一只老母鸡,用的时候就下蛋,这也是生成器的特性
>>> chicken=('鸡蛋%s' %i for i in range(5))
>>> chicken
<generator object <genexpr> at 0x10143f200>
>>> next(chicken)
'鸡蛋0'
>>> list(chicken) #因chicken可迭代,因而可以转成列表
['鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4',] #3、优点:省内存,一次只产生一个值在内存中
既然有了列表生成式,为什么还出现生成器生成式来生成列表,这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
生成器函数和普通函数之间的区别?
1.生成器函数中有yield关键字。
2.生成器函数执行后不会立即执行,而是返回一个生成器。
def func():
print("你好")
yield 1
print("中国")
yield 2
func()
print(func())
结果:
<generator object func at 0x000002DD23F698E0> #直接执行生成器函数后形成了一个生成器
如何让它打印执行?
def func():
print("你好")
yield 1
print("中国")
yield 2
func()
g=func()
print(g.__next__()) #生成器就是迭代器。
print(g.__next__())
结果:
你好
1
中国
2
python基础6 迭代器 生成器的更多相关文章
- python基础(9)-迭代器&生成器函数&生成器进阶&推导式
迭代器 可迭代协议和迭代器协议 可迭代协议 只要含有__iter__方法的对象都是可迭代的 迭代器协议 内部含有__next__和__iter__方法的就是迭代器 关系 1.可以被for循环的都是可迭 ...
- (转)python基础之迭代器协议和生成器(一)
一 递归和迭代 二 什么是迭代器协议 1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前 ...
- Python基础(冒泡、生成器、迭代器、列表与字典解析)
一.冒泡算法 冒泡算法,给定一组数据,从大到小排序或者从小到大排序,就像气泡一样 原理: 相邻的两个对象相比,大的放到后面,交换位置 交换位置通过a,b=b,a来实现 1.我们可以通过for循环来根 ...
- Python基础之迭代器和生成器
阅读目录 楔子 python中的for循环 可迭代协议 迭代器协议 为什么要有for循环 初识生成器 生成器函数 列表推导式和生成器表达式 本章小结 生成器相关的面试题 返回顶部 楔子 假如我现在有一 ...
- python基础之 迭代器回顾,生成器,推导式
1.迭代器回顾 可迭代对象:Iterable 可以直接作用于for循环的对象统称为可迭代对象:Iterable.因为可迭代对象里面存在可迭代协议,所以才会被迭代 可迭代对象包括: 列表(list) 元 ...
- 7th,Python基础4——迭代器、生成器、装饰器、Json&pickle数据序列化、软件目录结构规范
1.列表生成式,迭代器&生成器 要求把列表[0,1,2,3,4,5,6,7,8,9]里面的每个值都加1,如何实现? 匿名函数实现: a = map(lambda x:x+1, a) for i ...
- python基础之迭代器协议和生成器
迭代器和生成器补充:http://www.cnblogs.com/luchuangao/p/6847081.html 一 递归和迭代 略 二 什么是迭代器协议 1.迭代器协议是指:对象必须提供一个ne ...
- python基础8 -----迭代器和生成器
迭代器和生成器 一.迭代器 1.迭代器协议指的是对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前退) 2. ...
- Python基础4 迭代器,生成器,装饰器,Json和pickle 数据序列化
本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 孩子,我现在有个需 ...
随机推荐
- Azure ARM (16) 基于角色的访问控制 (Role Based Access Control, RBAC) - 使用默认的Role
<Windows Azure Platform 系列文章目录> 今天上午刚刚和客户沟通过,趁热打铁写一篇Blog. 熟悉Microsoft Azure平台的读者都知道,在老的Classic ...
- 开发中mysql和oracle的区别
首先就不描述mysql与oracle在整个数据库系统上的区别了,仅从程序员开发的角度来说: 1.主键: mysql一般会用到一个自增的属性,例如设置一个id字段,类型设置为auto increment ...
- global,local,static的区别
1.在函数内部使用global关键字定义的变量可以成为全局变量,如果该变量已经被定义了,那么他的值就是原来的值,否则就是一个新的全局变量(一句话:已存在就不再创建): <?php $a=1; f ...
- 简洁灵活的前端框架------BootStrap
前 言 Bootstrap,来自 Twitter,是目前很受欢迎的前端框架.Bootstrap 是基于 HTML.CSS.JAVASCRIPT 的,它简洁灵活,使得 Web 开发更加快捷.[1] ...
- Apache Spark 2.2.0 中文文档 - SparkR (R on Spark) | ApacheCN
SparkR (R on Spark) 概述 SparkDataFrame 启动: SparkSession 从 RStudio 来启动 创建 SparkDataFrames 从本地的 data fr ...
- SGU180(树状数组,逆序对,离散)
Inversions time limit per test: 0.25 sec. memory limit per test: 4096 KB input: standard output: sta ...
- Judge Route Circle
Initially, there is a Robot at position (0, 0). Given a sequence of its moves, judge if this robot m ...
- SQLserver学习(四)——T-SQL编程之事务、索引和视图
今天来分享下T-SQL高级编程中的事务.索引.视图,可以和之前的SQL server系列文章结合起来. 一.事务 事务(TRANSACTION)是作为单个逻辑工作单元执行的一系列操作,这些操作作为一个 ...
- 搭建git远程服务器三步骤
以前都是使用git,这次由于工作需要,需要自己搭建一个远程git服务器.根据网上的 介绍,捣鼓了一下午,终于把远程git服务器搞定了,这里,做个总结. 搭建git远程服务,首先要安装git和ssh,以 ...
- c# xml操作类 比较齐全
using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Secu ...