1.可迭代对象:在逻辑上它保存了一个序列,在迭代环境中依次返回序列中的一个元素值。
可迭代对象不一定是序列,但是序列一定是可迭代对象
2.迭代协议:.__next__()方法。
- 任何对象只要实现了迭代协议,则它就是一个迭代器对象
- 迭代器对象调用
.__next__()方法,会得到下一个迭代结果 - 在一系列迭代之后到达迭代器尾部,若再次调用
.__next__()方法,则会触发StopIteration异常 - 迭代器在Python中是用C语言的速度运行的,因此速度最快
3.Python3提供了一个内置的next()函数,它自动调用迭代器的.__next__()方法。即给定一个迭代器对象x,next(x)等同于x.__next__()
4.内置的iter()函数用于从序列、字典、set以及其他可迭代对象中获取迭代器。
-
对任何迭代器对象
iterator,调用iter(iterator)返回它本身 -
迭代器对象实现了迭代协议
-
文件对象本身是一个迭代器对象。即文件对象实现了迭代协议,因此打开多个文件会返回同一个文件对象
-
列表、元组、字典、
set、字符串等不适迭代器对象,他们没有实现迭代协议。因此每次调用iter()均返回一个新迭代器对象。他们支持安装多个迭代器,每个迭代器状态不同- 在原地修改列表、
set、字典时,会实时反映到它们的迭代器上
- 在原地修改列表、
5.文件迭代器:文件对象本身是一个迭代器(这里文件对象要是读打开)。它的.__next__()方法每次调用时,返回文件中的下一行。当到达文件末尾时,.__next__()方法会引发StopIteration异常。
.readline()方法在到达文件末尾时返回空字符串
6.字典的迭代器:字典的迭代器在迭代环境中,每次迭代返回的是一个键。
7.扩展的列表解析表达式:
[ x+y for x in 'abc' if x!='a' for y in 'lmn' if y!='l']
其通用结构为:
[ expression for target1 in iterable1 [if condition1]
for target2 in iterable2 [if condition2]
....]
我们总是可以用
for循环手动构建列表解析表达式的结果,但是列表解析表达式性能更好
8.for循环、列表解析、in成员关系测试、map()内置函数、sorted()内置函数、zip()内置函数等都是用迭代协议来完成工作
9.常见的迭代函数:
map(func,iterable):它将函数func应用于传入的迭代器的每个迭代返回元素,返回一个新的迭代器,函数执行结果作为新迭代器的迭代值
map()可以用于多个可迭代对象:map(func,[1,2,3],[2,3,4]),其中func(first,second)的两个参数分别从两个可迭代对象中获取,函数结果作为新迭代器的迭代值
zip(iterable1,iterable2,...):它组合可迭代对象iterable1、iterable2、...中的各项,返回一个新的迭代器。新迭代器长度由iterable1、iterable2、...最短的那个决定。
enumerate(iterable,start):返回一个迭代器对象,它迭代结果是每次迭代返回一个(index,value)元组
filter(func,iterable):返回一个迭代器对象,它的迭代结果得到iterable中部分元素,其中这些元素使得func()函数返回为真
reduce(func,iterable,initial):对iterable中每一项成对地运行func,返回最终值
reduce函数位于functools包内
-
any(iterable):只要可迭代对象iterable迭代返回的某个元素为真则返回True -
max(iterable,key=func):返回最大元素。若指定func,则返回是func(num)最大的那个元素
11.Python3中,range对象不支持.__next__(),因此它本身不是迭代器,而map、zip、filter对象都是迭代器。
12.字典的视图:键视图、值视图、字典视图都没有.__next__()方法,因此他们都不是迭代器
13.通常列表解析执行速度最快,map()速度次之,for循环速度最慢。前两者以C语言速度执行、后者在Python虚拟机上执行
14.生成器函数:编写为常规的def语句,但是用yield语句一次返回一个结果。每次使用生成器函数时会继续上一轮的状态。
生成器函数会保存上次执行的状态
定义生成器函数的语法为:
def genFunc(num):
for i in range(num):
yield i**2
- 生成器函数执行时,得到一个生成器对象,它
yield一个值,而不是返回一个值。- 生成器对象自动实现迭代协议,它有一个
.__next__()方法 - 对生成器对象调用
.__next__()方法会继续生成器函数的运行到下一个yield结果或引发一个StopIteration异常
- 生成器对象自动实现迭代协议,它有一个
yield语句会挂起生成器函数并向调用者发送一个值。当下一轮继续时,函数会在上一个yield表达式返回后继续执行,其本地变量根据上一轮保持的状态继续使用- 生成器函数运行代码随时间产生一系列的值,而不是一次性计算它们。这会节约内存并允许计算时间分散。
15.for循环(及其它迭代环境)通过重复调用.__next__()方法直到捕获一个异常。若一个不支持迭代协议的对象想用工作在这种环境中,for循环会尝试使用索引协议迭代。
16.生成器对象有一个.send(arg)方法。该方法会将arg参数发送给生成器作为yield表达式的返回值,同时生成器会触发生成动作(相当于调用了一次.__next__()方法。
yield表达式的返回值和生成值是不同的。
返回值是用于生成器函数内部,yield表达式默认返回值为None;
而生成值是用于生成器函数外部的迭代返回。
-
要想启动生成器,可以直接使用
next(generatorable)函数,也可以使用generatorable.send(None)方法,或者generatorable.__next__()方法next(generatorable)函数相当于使用generatorable.send(None)方法 -
generatorable.send(None)方法会在传递yield表达式的值(默认为None返回值),下一轮迭代从yield表达式返回开始每一轮挂起时,
yield表达式 yield 一个数,但是并没有返回(挂起了该yield表达式)
17.生成器表达式:类似于列表解析,但是它是在圆括号中的,而不是方括号中的。
- 生成器表达式返回的是一个生成器对象
- 列表解析的结果等同于
list()内参数为一个生成器表达式 - 当生成器表达式在其他括号之内时,它本身的圆括号可以不写
- 同样的迭代可以用生成器函数或者一个生成器表达式
- 生成器函数可以包含更多的逻辑
- 生成器表达式更简洁,没有函数调用产生生成器的过程
- 生成器函数与生成器表达式支持自动迭代与手动迭代
- 生成器对象本身是迭代器,因此只支持一个活跃的迭代器。
18.生成器函数可以有return,它可以出现在函数内任何地方。生成器函数内遇到return则触发StopIteration异常,同时return的值作为异常说明
19.可以调用生成器对象的.close()方法强制关闭它。这样再次给它send()任何信息,都会抛出StopIteration异常,表明没有什么可以生成的了
20.yield from:从PEP 380引入的新特性。
-
yield from可以将一个大的生成器切分成小生成器:def generator(): #该生成器yield数字[0~19] for i in range(10): yield i for j in range(10,20): yield j如果你想切分成两个迭代器,可以这么做:
def generator2(): for i in range(10): yield i def generator3(): for j in range(10): yield j def generator(): for i in generator2(): yield i for j in generator3(): yield j
引入yield from之后你可以这么做:
```
def generator2(): for i in range(10): yield i def generator3(): for j in range(10): yield j def generator(): yield from generator2() yield from generator3()
* `yield from`能实现代理生成器:
def generator(): inner_gen=generator2() yield from inner_gen #为了便于说明,这里分两行写 gen=generator()
* 对`inner_gen`迭代产生的每个值都直接作为`gen` yield值
* 所有`gen.send(val)`发送到`gen`的值`val`都会被直接传递给`inner_gen`。
* `inner_gen`抛出异常:
* 如果`inner_gen`产生了`StopIteration`异常,
则`gen`会继续执行`yield from`之后的语句
* 如果对`inner_gen`产生了非`StopIteration`异常,则传导至`gen`中,
导致`gen`在执行`yield from`的时候抛出异常
* `gen`抛出异常:
* 如果`gen`产生了除`GeneratorExit`以外的异常,则该异常直接 throw 到`inner_gen`中
* 如果`gen`产生了`GeneratorExit`异常,或者`gen`的`.close()`方法被调用,
则`inner_gen`的`.close()`方法被调用。
* `gen`中`yield from`表达式求职结果是`inner_gen`迭代结束时抛出的`StopIteration`异常的第一个参数
* `inner_gen`中的`return xxx`语句实际上会抛出一个`StopIteration(xxx)`异常,
所以`inner_gen`中的`return`值会成为`gen`中的`yield from`表达式的返回值。