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 ...
随机推荐
- SLAM中的非线性优化
总结一下SLAM中关于非线性优化的知识. 先列出参考: http://jacoxu.com/jacobian%E7%9F%A9%E9%98%B5%E5%92%8Chessian%E7%9F%A9%E9 ...
- LeetCode 841:钥匙和房间 Keys and Rooms
题目: 有 N 个房间,开始时你位于 0 号房间.每个房间有不同的号码:0,1,2,...,N-1,并且房间里可能有一些钥匙能使你进入下一个房间. 在形式上,对于每个房间 i 都有一个钥匙列表 ...
- HTTPS 相关问题
什么是 HTTPS? HTTPS,是指超文本传输安全协议(Hypertext Transfer Protocol Secure),是一种在 HTTP 协议基础上进行传输加密的安全协议,能够有效保障数据 ...
- C# 5.0 新特性之异步方法(AM)
Ø 前言 C# Asynchronous Programming(异步编程)有几种实现方式,其中 Asynchronous Method(异步方法)就是其中的一种.异步方法是 C#5.0 才有的新特 ...
- Chrome教程之使用Chrome DevTools命令菜单运行命令
1.模拟移动设备 点击 Toggle Device Toolbar 2.限制网络流量和 CPU 占用率 要限制网络流量和 CPU 占用率,请从 Throttle 列表中选择 Mid-tier mobi ...
- RESTful及API设计(原)
RESTful是一种架构风格,是由Fielding博士在自己的博士论文中提出并详细论述的. 它是用于指导web系统设计的,而指导API设计只是它的一小部分功能而已,如果只用它指导API设计就太大材小用 ...
- C# if else-if 语句
一.作用 用来处理多条件的区间性的判断. 二.语法 if(判断条件) { 要执行的代码; } else if(判断条件) { 要执行的代码; } else if(判断条件) { 要执行的代码; } e ...
- 高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP)
高性能TcpServer(C#) - 1.网络通信协议 高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP) 高性能TcpS ...
- Java构造函数执行顺序
首先执行基类的构造函数 然后执行派生类的构造函数之外的初始化语句 最后执行派生类的构造函数 在Java中,如果派生类构造函数需要调用基类的构造函数,那么基类构造函数必须作为派生类构造函数的第一句话.在 ...
- 【原创】CentOS 7 安装redis 5
1.下载redis安装包 cd /softwares/ wget http://download.redis.io/releases/redis-5.0.5.tar.gz 2.解压redis-5.0. ...