迭代器协议:

1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个Stopiteration异常,以终止迭代(只能往后走不能往前退)

2.可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义_iter_方法)

3.协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(如for循环,sum,min,max函数等)使用迭代器协议访问对象

for循环机制:

for循环的本质:循环所有对象,全都是使用迭代器协议。

(字符串,列表,元组,字典,集合,文件对象)这些都不是可迭代对象,只不过在for循环时,调用了他们内部的_iter_方法,把他们变成了可迭代对象

然后for循环调用可迭代对象的_next_方法去取值,而且for循环会捕捉Stopiteration异常,以终止迭代。

s='abc'
s_i=s.__iter__()
print(s_i.__next__())
print(s_i.__next__())
print(s_i.__next__())
print(s_i.__next__())#抛StopIteration异常 >>>a
>>>b
>>>c
>>>a
Traceback (most recent call last):
b
File "E:/ch/Pylearning/Learning_09.py", line 115, in <module>
c
print(s_i.__next__())
StopIteration

for循环的本质:

l=[1,2,3]

for i in l:#i_l=l.__iter__()  i_l.__next__()
print(i)
#while循环完成for循环工作
s='qwer'
i=0
while i<len(s):
print(s[i])
i+=1

但while循环不能遍历字典、集合、文件。
能被for循环遍历的对象都有__iter__()方法。

f=open('a.txt','r+',encoding='utf-8')
iter_f=f.__iter__()
print(iter_f.__next__(),end='')
print(iter_f.__next__(),end='')
print(iter_f.__next__(),end='')
print(iter_f.__next__(),end='')

for循环就是基于迭代器协议提供了一个统一的可以遍历所有对象的方法,在遍历之前,先调用对象的__iter__方法将起转换成一个迭代器,然后使用迭代器协议去实现循环访问,这样所有的对象就都可以通过for循环来遍历了。

用while循环模拟for循环机制:

dic={'a':1,'b':2,'c':3}
iter_d=dic.__iter__()
while True:
try:
print(iter_d.__next__())
except StopIteration:
print('迭代完成')
break >>>a
b
c
迭代完成

next()方法是系统自带方法,本质上也是调用__next__()方法

l=[1,2,3]
a=l.__iter__()
print(next(a))#next()————》调用a.__next__()方法

只要遵循迭代器协议,那么该对象就是可迭代对象

生成器:

生成器:可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他的数据类型需要调用自己内置的__iter__()方法),所以生成器就是可迭代对象

生成器分类及在python中的表现形式:

1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结构。yield语句一次返回一个结果,每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行.yield相当于return,但是可以在一个函数中使用多次。yield相当于封装了__iter__()方法,直接得到生成器对象。

def test():
yield 1
yield 2
yield 3
yield 4 g=test()
print(g.__next__())
print(g.__next__())
print(g.__next__())
print(g.__next__()) >>>1
2
3
4

2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表

三元表达式

#三元表达式
name='ss'
#如果name='alex'返回'sb'否则返回'hand'
r='sb' if name=='alex' else 'hand'
print(r)

列表解析:

#将列表中放入10个鸡蛋
l1=[]
for i in range(1,11):
l1.append('鸡蛋%s'%i)
print(l1) >>>['鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9', '鸡蛋10'] #列表解析的方式
l2=['鸡蛋%s'%i for i in range(1,11)]
print(l2) >>>['鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9', '鸡蛋10']
l3=['鸡蛋%s'%i for i in range(1,11) if i<5]#没有四元表达式
print(l3) >>>['鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4']

生成器表达式:

1.把列表解析的[]换成()得到的就是生成器表达式

2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存

l2=['鸡蛋%s'%i for i in range(1,11)]
#生成器:
l4=('鸡蛋%s'%i for i in range(1,11))
print(l4)
print(l4.__next__())
print(l4.__next__())
print(next(l4))
print(next(l4)) >>><generator object <genexpr> at 0x000001FFD4A3C1A8>
鸡蛋1
鸡蛋2
鸡蛋3
鸡蛋4

3.pyhton不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如:sum函数是python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和:

l=[1,2,3,4,5,6,7,8,9,7,4,6,4,1]

print(sum([1,2,3,4,5,6]))
print(sum(i for i in range(0,1000000)))#生成器表达式方式

yield:

使用第一次__next__()则表示函数运行到第一个yield,使用第二次__next__()则表示函数从第一个yield运行到第二个yield,以此类推。。。

import time

def test():
print('开始生孩子了')
yield '我'
time.sleep(3)
print('又开始生孩子了')
yield '我的孩子'
time.sleep(3)
print('又又开始生孩子了')
yield '我的孩子的孩子' res=test() print(res.__next__())
print(res.__next__())
print(res.__next__()) >>>开始生孩子了

>>>又开始生孩子了
我的孩子
>>>又又开始生孩子了
我的孩子的孩子

生成器函数:

例1:

def product_baozi():
for i in range(1,100):
print('生产包子中')
yield '包子%s'%i
print('卖包子') p=product_baozi()
baozi1=p.__next__()
print(baozi1)
baozi2=p.__next__()
print(baozi2) >>>生产包子中
包子1
卖包子

例2:

def product_egg():
for i in range(1,1000):
yield '第%s个鸡蛋'%i p=product_egg()
print(p.__next__())
print(p.__next__())
print(p.__next__())
print(p.__next__())
print(p.__next__())
print(p.__next__())
print(p.__next__())
print(p.__next__()) >>>第1个鸡蛋
第2个鸡蛋
第3个鸡蛋
第4个鸡蛋
第5个鸡蛋
第6个鸡蛋
第7个鸡蛋
第8个鸡蛋

for循环遍历生成器:

def product_egg():
for i in range(1,1000):
yield '第%s个鸡蛋'%i p=product_egg() for i in product_egg():
print(i)

生成器总结:

def get_populartion():
with open('xxx','r',encoding='utf-8') as f:
for i in f :
yield i p=get_populartion()
print('全国总人口约为%d'%sum(eval(i)['人口'] for i in p ))

def test():
for i in range(0,4):
yield i t=test()
# for i in t:
# print(i)
t1=(i for i in t)
t2=(i for i in t1)
print(list(t1))
print(list(t2)) >>>[0, 1, 2, 3]
>>>[]

补充
send()用法,send与next和__next__()都可以使生成器往下执行
yield 2相当于return,控制的是函数的返回值
x=yield的另外一个特性,接收send传过来的值,赋值给x
# send()用法,send与next和__next__()都可以使生成器往下执行
# yield 2相当于return,控制的是函数的返回值
# x=yield的另外一个特性,接收send传过来的值,赋值给x
def test():
print('开始第一次')
first=yield 1
print('开始第二次',first)
yield 2
print('开始第三次')
yield 3 t=test()
print(t.__next__()) t1=t.send('啊啊啊啊')
print(t1) >>>开始第一次
1
开始第二次 啊啊啊啊
2

生产者消费者模型:

#两个函数并行:
#生产者消费者模型
def consumer(name):
print('%s准备吃包子了'%(name))
time.sleep(0.5)
while True:
g=yield
print('%s开始吃%s包子了'%(name,g)) def producer():
p1=consumer('alex')
p1.__next__()
for i in range(1,10):
time.sleep(0.5)
p1.send('第%d'%i) producer() >>>alex准备吃包子了
alex开始吃第1包子了
alex开始吃第2包子了
alex开始吃第3包子了
alex开始吃第4包子了
alex开始吃第5包子了
alex开始吃第6包子了
alex开始吃第7包子了
alex开始吃第8包子了
alex开始吃第9包子了

python_10 迭代器和生成器的更多相关文章

  1. Python 从零学起(纯基础) 笔记 之 迭代器、生成器和修饰器

    Python的迭代器. 生成器和修饰器 1. 迭代器是访问集合元素的一种方式,从第一个到最后,只许前进不许后退. 优点:不要求事先准备好整个迭代过程中的所有元素,仅仅在迭代到某个元素时才计算该元素,而 ...

  2. Python之模块,迭代器与生成器

    本节涉及内容: 1. 迭代器和生成器 2. 递归 3. 字符串格式化 4. 模块 内置模块 自定义模块 第三方模块 5. 序列化的模块 json pickle (一). 迭代器和生成器: 迭代器:  ...

  3. Python之迭代器和生成器

    Python 迭代器和生成器 迭代器 Python中的迭代器为类序列对象(sequence-like objects)提供了一个类序列的接口,迭代器不仅可以对序列对象(string.list.tupl ...

  4. python学习笔记四 迭代器,生成器,装饰器(基础篇)

    迭代器 __iter__方法返回一个迭代器,它是具有__next__方法的对象.在调用__next__方法时,迭代器会返回它的下一个值,若__next__方法调用迭代器 没有值返回,就会引发一个Sto ...

  5. 【Python】迭代器、生成器、yield单线程异步并发实现详解

    转自http://blog.itpub.net/29018063/viewspace-2079767 大家在学习python开发时可能经常对迭代器.生成器.yield关键字用法有所疑惑,在这篇文章将从 ...

  6. 15.python的for循环与迭代器、生成器

    在前面学习讲完while循环之后,现在终于要将for循环这个坑填上了.之所以拖到现在是因为for循环对前面讲过的序列.字典.集合都是有效的,讲完前面的内容再来讲for循环会更加容易上手. 首先,for ...

  7. Python: 迭代器与生成器小结

    迭代器与生成器的区别: 1. 迭代器由Class对象创建. 生成器由包含yield表达的Function对象或者Generator Expression创建. 2. 迭代器的原理: (1)由Itera ...

  8. Python中的迭代器和生成器

    本文以实例详解了python的迭代器与生成器,具体如下所示: 1. 迭代器概述: 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后 ...

  9. Python可迭代对象、迭代器和生成器

    Python可迭代对象.迭代器和生成器 python 函数 表达式 序列 count utf-8 云栖征文 python可迭代对象 python迭代器 python生成器 摘要: 8.1 可迭代对象( ...

随机推荐

  1. 2017-9-3模拟赛T2 取数(win)

    题目 题解 做法1: 直接暴力枚举每个数是否被选出,计算平均数-中位数,并与当前答案进行比较.复杂度O(2^n),能过60%的数据. 做法2: 将每个数排序后枚举中位数. 首先,取奇数个数一定更优.容 ...

  2. java面向对象编程(六)--四大特征之继承

    本文将介绍继承.方法重载和方法覆盖.其中方法重载和方法覆盖是在讲多态时必须要清楚的一个知识点. 一.继承 1.继承的概念 继承可以解决代码复用,让我们的编程更加靠近人类思维.当多个类存在相同的属性(变 ...

  3. sed语法2

    sed命令是一个面向字符流的非交互式编辑器,也就是说sed不允许用户与它进行交互操作.sed是按行来处理文本内容的.在shell中,使用sed来批量修改文本内容是非常方便的. sed命令的选项 sed ...

  4. 学习HashMap随笔(更新中)

    1.先来一个HashMap和HashTable的区别: HashMap线程不安全,键值可以为空 HashTable线程安全,键值不可以为空 2.hashmap我理解的是把数组存储和链表存储相结合了 具 ...

  5. 剑指Offer 28. 数组中出现次数超过一半的数字 (数组)

    题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2. ...

  6. Windows CMD 支持ls命令

    /********************************************************************** * Windows CMD 支持ls命令 * 说明: * ...

  7. C语言笔记变量与数据类型

    目录 1.转义字符 2.常量与变量 2.1 什么是常量和变量 2.2 内存 2.3 变量的内存机制 2.4 变量命名规则 2.5 变量的定义 2.6 常量的定义 2.7 计算机内存字节顺序 2.8 局 ...

  8. 《Linux内核原理与分析》第六周作业

    课本:第五章 系统调用的三层机制(下) 中断向量0x80和system_call中断服务程序入口的关系 0x80对应着system_call中断服务程序入口,在start_kernel函数中调用了tr ...

  9. Mat的详解

    [转]OpenCV中Mat的详解 每次碰到Mat都得反复查具体的用法,网上的基础讲解不多,难得看到一篇,赶快转来收藏~ 原文地址:http://www.opencvchina.com/thread-1 ...

  10. esxi5 的tart命令使用注意点

    esxi5.0 注意tar命令参数使用和centos6稍微有点不一样,注意下 注意需要把-f参数单独分离出来,紧接着文件.   而不能和cz命令一起用 ~ # touch abc.txt ~ # ec ...