Python进阶-V 迭代器(Iterator)、生成器(Generator)函数
一、迭代器
1、可循环的有哪些,即可用for语句或者while语句的数据类型有哪些?
字符串(str)、列表(list)、元组(tuple)、字典(dic)、集合(set)、枚举类(enumerate)
还有哪些非数据类型,但是可以循环的?
range(10), 文件句柄:f = open('filename',mode='r',enconding='utf-8')
2、查看这些可循环的数据类型或者函数或者文件句柄
都有哪些共同的东西:(求交集,想到集合(set)的操作了)。
还要引入一个内置函数dir()
print(dir())
print(dir(' '))
由返回结果可以看到,dir带参数时,返回该参数的属性、方法列表。
不带参数时,返回当前范围内的变量、方法和定义的类型列表;
# 先可以求list和str的交集方法了
str_method_li = set(dir(''))
list_method_li = set(dir([]))
res = str_method_li & list_method_li
print(res)
# 还是由很多共有的方法,加大力度
tuple_m_li = set(dir(()))
dic_m_li = set(dir({}))
range_m_li = set(dir(range(5)))
set_m_li = set(dir(set({1, 2, 3, 4})))
res = res & tuple_m_li & dic_m_li & range_m_li & set_m_li
print(res)
# 还是由很多,我们还是看一看交集中一个双下方法名:__iter__
# 补充说明一下“双下方法”:方法名中开头和结果都带有两个下滑线的,即叫双下方法!它是python中用C实现的方法!
# 这个__iter__, 跟可迭代对应的英文iterable很像!
我们可以得出结论:
只要是能被for循环的数据类型,就一定拥有__iter__方法!
print([].__iter__())
# 运行结果为:<list_iterator object at 0x000001C2AD37B4A8>
# 即得到list的迭代器对象,因此我们可以判断,该方法返回的是一个迭代器(iterator)!
iterator = 'lov'.__iter__()
print(dir(iterator))
# 看到迭代器中的方法中,有一个双下方法:__next__,我们来看看它得到的是什么?
print(iterator.__next__())
# 返回的是字符串中的第一字母,再执行一次!
print(iterator.__next__())
# 返回的是字符串中的第二字母,再执行一次!
print(iterator.__next__())
# 返回的是字符串中的第三字母,再执行一次!
#print(iterator.__next__()) # 报错 StopIteration
# 这说明迭代器可以一个一个取集合中的元素,只到没有时,抛出异常!
总结一下:
#Iterable 可迭代的 -- > __iter__ #只要含有__iter__方法的都是可迭代的
[].__iter__() 迭代器 -- > __next__ #通过next就可以从迭代器中一个一个的取值 延申一下:
只要含有__iter__方法的都是可迭代的 —— 可迭代协议
自定义一个类型,可以用来迭代
from collections import Iterable
from collections import Iterator class A:
def __next__(self):pass
def __iter__(self):pass a = A()
print(isinstance(a, Iterable))
print(isinstance(a, Iterator))
结果都为True,说明该类即可被迭代,也是迭代器!
3、迭代器的概念
迭代器协议:内部含有__next__方法和__iter__方法的就是迭代器
小结一下:
迭代器协议和可迭代协议
可以被for循环的都是可迭代的
可迭代的内部都有__iter__方法
只要是迭代器 一定可迭代
可迭代的.__iter__()方法就可以得到一个迭代器
迭代器中的__next__()方法可以一个一个的获取值
我们可以推导一下, for循环其实就是在使用迭代器
只有是可迭代对象的时候 才能用for
当我们遇到一个新的变量,不确定能不能for循环的时候,就判断它是否可迭代
4、迭代器的好处
从容器中一个一个取值,会将所有的值取到;
节省内存空间:
迭代器不会在内存中再占用一大块内存;
每次next,都会给我们一个新的
二、生成器函数
1、生成器的引入场景
#如果想要一个包含2百万个ILOVEU的字符串,如何取得?如此取只会得到最后一个def func():
for i in range(2000000):
i = 'ILOVEU%s'%i
return i print(func())
改进一下:
def generate_str():
li = []
for i in range(200):
s = 'ILOVEU No' + str(i) + ' '
# print(s)
li.append(s)
return ','.join(li) print(generate_str())
如此做的确可以生成一个包含200万个’ILOVEU No%d‘的字符串,
但是如此使用迭代器无优势!因为它一次性在内存中生成,浪费内存空间,而迭代器的优点恰恰是节省内存!
总结:
理清迭代器的原理,可以理解for循环的是如何工作的,另外可以对了解生成器做铺垫!
迭代器虽然有很多优点,如节省内存空间,但是不能满足我们的所有需求;
如果我们平时在写代码过程中,要产生大量的数据,又不希望一次性在内存中生成,而且还要处处使用它,基于此种情况,
必须有我们自己写的迭代器!它就是生成器!
2、生成器有两种表现形式:
1)、生成器函数 --- 本质上就是我们自己写的函数
2)、生成器表达式
3、生成器函数的定义:
只要含有yield关键字的函数都是生成器函数
ef generator():
print(1)
#return 'a'
yield 'b' # yield不能和return共用且需要写在函数内 res = generator() # 生成器函数 : 执行之后会得到一个生成器作为返回值
print(res) # <generator object generator at 0x0000019C239AD4C0> def generator_full():
print(1)
yield 'a' # yield不会结束函数
print(2)
yield 'b'
yield 'c'
g = generator_full()
print(dir(g)) # 它有'__iter__' ret = g.__next__()
print(ret) # 执行步骤:1)执行g.__next__()双下函数;2)调用generator_full函数;3) print(1);4)执行:yield 'a' 返回a,但不退出函数,等待
ret = g.__next__()
print(ret)# 执行步骤:1)执行g.__next__()双下函数;2)调用generator_full函数;3) print(2); 4)yield 'b' 返回b,但不退出函数,等待
# ret = g.__next__()
# print(ret)# 执行步骤:1)执行g.__next__()双下函数;2)调用generator_full函数;3)yield 'c' 返回c,但不退出函数,等待
# ret = g.__next__()
# print(ret)# 执行步骤:1)执行g.__next__()双下函数;2)调用generator_full函数;3)发现没有yield,报错StopIteration for i in g: # 接着上面的继续迭代剩下的元素
print(i) # 用for循环迭代后,无法再迭代了!
# ret = g.__next__()
# print(ret)
4、使用生成器函数来生成200万个“ILOVEU No%d”
def s_generator():
for i in range(200):
yield 'ILOVEU No%d'%i s_g = s_generator()
# for i in s_g:
# print(i)
继续深入
#需求:我要取出前50个ILOVEU
for i in range(50):
print(s_g.__next__()) i = 0
# 发现是按序号接着取元素,从ILOVEU No50开始取
while i < 50:
i += 1
print('----',s_g.__next__())
# 生成器与迭代器一样,会记录当前取到元素的位置,以及下一个元素的位置,随时都可以得到下一个元素! # 对比for循环列表(list,不是迭代器,但是可以迭代)
li = [2, 4, 6, 8, 10]
for i in li:
print(i)
if i == 6:
break for j in li:
print(j)
# 我们发现,没有从停止的位置的下一个位置取元素,而是重新取出所有元素!
# 原因不是list不是迭代器,for循环时,已经将其转换为迭代器,
# 而是,两次for的时候的迭代器不是同一个! #我们再来看生成器s_generator的例子
g1 = s_generator()
g2 = s_generator()
print(g1.__next__())
print(g2.__next__())
# 结果都是ILOVEU No0,说明同一个生成器(同时也是迭代器),__next__时才会记住元素位置
5、监听文件输入的内容,实时打印到命令行中
#普通方法:
def trip(file_path):
f = open(file_path, encoding='utf-8')
while 1:
line = f.readline() # 每次读一行
if line.strip():
print(line.strip()) # 缺点:不能返回line,如果return,循环就终止了 #trip('../day12_func/user_info') def monitor(file_path):
f = open(file_path, mode='r', encoding='utf-8')
while 1:
line = f.readline()
if line.strip():
yield line.strip() g = monitor('../day12_func/user_info')
for i in g:
if 'python' in i:
print('*****', i) ##修改文件后,按ctrl+s才能有效果!打印结果!
Python进阶-V 迭代器(Iterator)、生成器(Generator)函数的更多相关文章
- python 进阶篇 迭代器和生成器深入理解
列表/元组/字典/集合都是容器.对于容器,可以很直观地想象成多个元素在一起的单元:而不同容器的区别,正是在于内部数据结构的实现方法. 所有的容器都是可迭代的(iterable).另外字符串也可以被迭代 ...
- Python进阶之迭代器和生成器
可迭代对象 Python中任意的对象,只要它定义了可以返回一个迭代器的__iter__方法,或者定义了可以支持下标索引的__getitem__方法,那么它就是一个可迭代对象.简单来说,可迭代对象就是能 ...
- Python 闭包、迭代器、生成器、装饰器
Python 闭包.迭代器.生成器.装饰器 一.闭包 闭包:闭包就是内层函数对外层函数局部变量的引用. def func(): a = "哈哈" def func2(): prin ...
- python设计模式之迭代器与生成器详解(五)
前言 迭代器是设计模式中的一种行为模式,它提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示.python提倡使用生成器,生成器也是迭代器的一种. 系列文章 python设计模 ...
- python is、==区别;with;gil;python中tuple和list的区别;Python 中的迭代器、生成器、装饰器
1. is 比较的是两个实例对象是不是完全相同,它们是不是同一个对象,占用的内存地址是否相同 == 比较的是两个对象的内容是否相等 2. with语句时用于对try except finally 的优 ...
- Python语言的循环语句、迭代器与生成器、函数学习
while循环语句 无限循环 我们可以通过设置条件表达式永远不为false来实现无限循环,实例如下: for语句 Python for循环可以遍历任何序列的项目,如一个列表或者一个字符串 Python ...
- 【python基础】迭代器和生成器函数
1.迭代器协议: 1.迭代器协议是指:对象必须提供一个 __next__() 方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代(只能往后走不能往前退) ...
- Python学习--07迭代器、生成器
迭代 如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration). Python里使用for...in来迭代. 常用可迭代对象有 ...
- Python学习笔记 - 迭代器Iterator
我们已经知道,可以直接作用于for循环的数据类型有以下几种: 一类是集合数据类型,如list.tuple.dict.set.str等: 一类是generator,包括生成器和带yield的genera ...
随机推荐
- 机器学习之感知器和线性回归、逻辑回归以及SVM的相互对比
线性回归是回归模型 感知器.逻辑回归以及SVM是分类模型 线性回归:f(x)=wx+b 感知器:f(x)=sign(wx+b)其中sign是个符号函数,若wx+b>=0取+1,若wx+b< ...
- vuex 源码解析(四) mutation 详解
mutation是更改Vuex的store中的状态的唯一方法,mutation类似于事件注册,每个mutation都可以带两个参数,如下: state ;当前命名空间对应的state payload ...
- 云原生生态周报 Vol. 11 | K8s 1.16 早知道
业界要闻 Pivotal 发布了完全基于 Kubernetes 的 Pivotal Application Service(PAS)预览版 这意味着 Pivotal 公司一直以来在持续运作的老牌 Pa ...
- JDBC与Druid简单介绍及Druid与MyBatis连接数据库
序言 java程序与数据建立连接,首先要从jdbc说起,然后直接上阿里认为宇宙最好的数据库连接池druid,然后再说上层程序对象与数据源映射关联关系的orm-mybatis. JDBC介绍 JDBC( ...
- 微信分享网页时自定义缩略图和简介(.net版本)
要实现微信分享网页时自定义缩略图和简介,需开发者在公众平台网站中创建公众号.获取接口权限后,通过微信JS-SDK的分享接口,来实现微信分享功能. 下面来说明实现步骤. 第一部分 准备步骤 步骤一:注册 ...
- 【转载】Visual Studio2017中如何设置解决方案中的某个项目为启动项目
在C#的应用程序开发过程中,一个完成的解决方案可能包含多个子项目,有时候需要设置某一个子项目为启动项目,在Visual Studio 2017集成开发工具中,设置解决方案中的某个项目为启动项目的操作方 ...
- CTF必备技能丨Linux Pwn入门教程——PIE与bypass思路
Linux Pwn入门教程系列分享如约而至,本套课程是作者依据i春秋Pwn入门课程中的技术分类,并结合近几年赛事中出现的题目和文章整理出一份相对完整的Linux Pwn教程. 教程仅针对i386/am ...
- c++和c动态申请二维数组
这是我面试中遇到的一道题,用c和c++分别申请一个二维数组,int **res,要求申请后的可以使用res[3][4]这一类防存方式. 这个是没有错误检查的版本. 答案: c++语言的版本 int * ...
- 使用 PXE+Kickstart 实现无人值守批量部署系统
一.废话两句 在云数据中心,一次几十台甚至几百台服务器上线,系统安装将变得非常繁琐,系统安装好了后还会涉及很多配置,如果一台台来安装的话工作量非常大.(虽然有加班费,开个玩笑)为了解决这个问题,我们需 ...
- springcloud学习之路: (四) springcloud集成Hystrix服务保护
Hystrix是一套完善的服务保护组件, 可以实现服务降级, 服务熔断, 服务隔离等保护措施 使用它可以合理的应对高并发的情况 做到保护服务的效果 1. 导入依赖 <dependency> ...