Python的迭代器与生成器
迭代器概念
声明:迭代器和生成器、装饰器,两者之间没有直连关系。
迭代和递归的概念请参考:https://www.cnblogs.com/guge-94/p/10509074.html
双下方法:双下划线的方法,如__name__();由C语言编写的,不止一种调用方式;
iterable(可迭代):拥有__iter__()方法的数据类型 --> 可迭代协议
iterator(迭代器):拥有__iter__()方法和__next__()方法 --> 迭代器协议
能够被for循环操作的数据类型都属于可迭代类型(即__iter__()方法);
可迭代数据类型加入__iter__()方法则可以将一个可迭代对象变成一个迭代器。(这里为什么不是加入__next__()方法我到现在没想明白)
特点
-
很方便使用,且只能取所有的数据取一次
-
节省内存空间
范例
print(dir([])) # dir():返回指定参数可使用的方法 print([1].__add__([2])) print([1]+([2])) #其实‘+’ 就是在调用__add__()方法,双下方法一般不直接调用。 print('__iter__' in dir(123)) print('__iter__' in dir('123')) # 判断数字和字符串中是否有可迭代方法 from collections import Iterable from collections import Iterator print(isinstance([],Iterator)) print(isinstance([],Iterable)) # 简单做一个判断,判断迭代协议与可迭代协议的真实性
生成器概念
- 生成器的本质就是迭代器(自己写的迭代器)
- 只要含有yield关键字的函数都是生成器函数;yield不可以和return共存,且需要写在函数内部
- 生成器函数执行之后会得到一个生成器作为返回值
- 生成器实现的两种方式:生成器函数和生成器表达式
特点
-
调用函数的之后函数不执行,返回一个生成器
-
每次调用next方法的时候会取到一个值
-
直到取完最后一个,在执行next会报错
范例
def generator(): print(1) yield 'a' print(2) yield 'b' yield 'c' g = generator() for i in g: print(i) ret = g.__next__() print(ret) ret = g.__next__() print(ret) ret = g.__next__() print(ret)
注意:生成器每次只去一次值,没取完的值也不会消失,在后续可以继续调用
生成器进阶
send使用
# 生成器函数进阶之send使用 def func1(): print('line1') line = yield 1 print(line,'sendline') print('line2') yield 2 f = func1() ret = f.__next__() print(ret) ret = f.send( 'one') print(ret)
-
send 获取下一个值的效果和next基本一致
-
只是在获取下一个值的时候,给上一yield的位置传递一个数据
-
第一次使用生成器的时候 必须用next获取下一个值
-
最后一个yield不能接受外部的值,即send不能用来传递最后一个yield
列表推导式
# 语法 [循环值 循环体 判断(判断语句可不写)] List = [i for i in range(30) if i%3 == 0] print(List)
生成器表达式
# 格式 # (循环值 循环体) List = (i for i in range(10)) for i in List: print(i)
- 生成器表达式与列表推导式几乎一某一样,除了最外边的包含符号;列表推导式是中括号,生成器表达式是小括号
- 列表推导式占用内存大,生成器表达式几乎不占用内存
字典推导式
# 将一个字典的key和value对调 mcase = {'a': 10, 'b': 34} mcase_frequency = {mcase[k]: k for k in mcase} print(mcase_frequency)
集合推导式
# 集合推导式和列表推导式差不多,多一个去重功能 squared = {x**2 for x in [1, -1, 2]} print(squared)
心若向阳,无谓悲伤!