迭代器与生成器
迭代器
可迭代
字符串、列表、元组、字典、集合都可以被for循环,说明他们都是可迭代的
# 迭代:对同一个数据进行多次相同的操作
# 递归:对自身进行多次调用
from collections import Iterable
l = [1, 2, 3, 4]
t = (1, 2, 3, 4)
d = {1: 2, 3: 4}
s = {1, 2, 3, 4}
print(isinstance(l, Iterable))
print(isinstance(t, Iterable))
print(isinstance(d, Iterable))
print(isinstance(s, Iterable))
可迭代协议
可以被迭代要满⾜的要求就叫做可迭代协议。可迭代协议的定义⾮常简单,就是内部实现了__iter__
() ⽅法。
l = [1, 2, 3, 4]
t = (1, 2, 3, 4)
d = {1: 2, 3: 4}
s = {1, 2, 3, 4}
print(dir(l))
print(dir(t))
print(dir(d))
print(dir(s))
可迭代的:内部必须含有⼀个__iter__
⽅法。
迭代器
l = [1, 2, 3, 4]
#print(type(l))
#print(type(l.__iter__()))
#print(type(l.__iter__().__iter__()))
#print(dir(l))
#print(dir(l.__iter__()))
l_iter = l.__iter__()
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
# 没有后续元素会抛出StopIteration异常
迭代器遵循迭代器协议:必须拥有__iter__
⽅法和__next__
⽅法。
丑!双下划线方法有意隐藏
魔法方法 Magic Method
__iter__()
--> iter()
__next__()
--> next()
for 将此过程自动化,为可迭代对象创建了一个迭代器,然后反复调用下一个元素直至捕获StopIteration异常。
- 不用for
l = [1, 2, 3, 4]
length = len(l)
l1 = iter(l)
while length:
print(next(l1))
length -= 1
- 异常处理
l = [1, 2, 3, 4]
l_iter = l.__iter__()
while True:
try:
item = l_iter.__next__()
print(item)
except StopIteration:
break
懒惰计算
条件表达式 if x and y,在x为false的情况下y表达式的值将不再计算。
而对于if x or y,当x的值为true的时候将直接返回,不再计算y的值
生成器
概念
Python中创建迭代器最方便的技术是使用生成器
生成器的语法实现类似于函数,但不返回值。
在 Python 中,使用了 yield 的函数被称为生成器(generator)
在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
生成器函数
⼀个包含yield关键字的函数就是⼀个⽣成器函数。yield可以为我们从函数中返回值,但是yield ⼜不同于return,return的执⾏意味着程序的结束,调⽤⽣成器函数不会得到返回的具体的值, ⽽是得到⼀个可迭代的对象。每⼀次获取这个可迭代对象的值,就能推动函数的执⾏,获取新的 返回值。直到函数执⾏结束。
import time
def genrator_func1():
a = 1
print('将a赋值')
yield a
b = 2
print('将b赋值')
yield b
g1 = genrator_func1()
print(g1,next(g1))
print(next(g1))
用 yield 实现斐波那契数列:
import sys
def fibonacci(n): # 生成器函数 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()
执行以上程序,输出结果如下:
0 1 1 2 3 5 8 13 21 34 55
send
send 获取下⼀个值的效果和next基本⼀致
只是在获取下⼀个值的时候,给上⼀yield的位置传递⼀个数据
注意事项:
- 第⼀次使⽤⽣成器的时候 是⽤next获取下⼀个值
- 最后⼀个yield不能接受外部的值
python 从右至左
def generator():
print(123)
content = yield 1
print('=========',content)
print(456)
yield 2
g = generator()
ret = g.__next__() #yield断点停止
print('***',ret)
ret = g.send('hello')
print('***',ret)
解析语法
有些时候的编程任务是基于另一个序列的处理来产生一系列的值
列表解析语法:
[expression for value in iterable if condition ]
一般的:
result = []
for value in iterable:
if condition:
result.append(expression)
-
把列表解析的[]换成()得到的就是⽣成器表达式
-
列表解析与⽣成器表达式都是⼀种便利的编程⽅式,只不过⽣成器表达式更节省内存
-
Python不但使⽤迭代器协议,让for循环变得更加通⽤。⼤部分内置函数,也是使⽤迭代器 协议访问对象的。
例如, sum函数是Python的内置函数,该函数使⽤迭代器协议访问对 象,⽽⽣成器实现了迭代器协议,所以,我们可以直接这样计算⼀系列值的和:
total = sum(k * k for k in range(1, n + 1))