这里面主要还是一些基础的知识,之前自己在印象笔记里面也有相应的整理的过程,总之相互结合,最后的目的是能够对知识点的掌握。
生成器:generator
- 单纯通过列表生成式有时会很占相应的内存空间
- 列表元素按照某种算法推算出来,可以在循环的过程中不断的推算出后续的元素,可以不用创建完整的list,可以节省大量的存储空间
- 一边循环一边计算的机制:generator
- 创建一个generator的方法:
- 把列表生成式的[]改为()
- 如果要打印出generator的每一个元素:通过next()函数获得返回值
- 改进每次都需要不断的next的操作,采用for循环来迭代(generator也是可以迭代的对象),不需要关心产生的StopIteration的错误
- 第二种方法:如果函数定义中包含了yield关键字,函数不再是普通函数,是generator函数,调用一个generator函数就会返回一个generator
- 工作原理:
- 在for循环的过程中不断的计算出下一个元素,并在适当的条件结束for循环
- 对于函数改成的generator来说,遇到return或执行到函数体最后一行语句就是结束generator指令,for循环结束
- 普通函数调用直接返回结果,generator函数的调用返回一个generator对象
- 案例:斐波拉契数列
几个小例子辅助理解:
# 采用for循环来迭代,不需要关心产生的StopIteration的错误
g = (x * x for x in range(10))
for n in g:
print(n)
# 打印结果如下
0
1
4
9
16
25
36
49
64
81
# 当推算的算法比较的复杂的时候,用列表生成式的for循环无法实现的时候,用函数实现比较好
# 用斐波拉契数列来说明
def fib(max):
n,a,b=0,0,1
while n<max:
print(b)
a,b=b,a+b
n=n+1
return "done"
print(fib(6))
# 打印结果
1
1
2
3
5
8
done
由上面的演算逻辑可知:fib函数定义了斐波拉契数列的推算规则,可以从第一个元素开,推算处后续的任意元素。这种逻辑类似与generator,将上面的代码中的print(b)改为yield b,就可以把fib函数变成generator函数
# 由于包含关键字,函数不再是一个普通函数,调用一个generator函数将会返回一个generator
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
print(fib(6))
# 运行结果
<generator object fib at 0x000002CFDD443C80>
附加理解:generator函数与普通函数的执行流程不同:
- 普通函数:顺序执行,遇到return或者是最后一行函数语句就返回
- 对于generator函数来说:每次调用next()的时候执行,遇到yield语句返回,再次执行时的时候返回yield语句处处继续执行
# 因此将上面的代码进行改进,不用next()来获取下一个返回值,直接用for循环迭代
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
for n in fib(6):
print(n)
# 打印结果如下:
# 没有获取return语句的返回值
1
1
2
3
5
8
想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
g=fib(6)
while True:
try:
x=next(g)
print('g:',x)
# 为了捕获StopIteration错误
except StopIteration as e:
print('Generator return value:' ,e.value)
break
# 打印结果如下:
g: 1
g: 1
g: 2
g: 3
g: 5
g: 8
Generator return value: done
迭代器:Iterable
for循环的数据类型的以下几种:
- 合数据类型:list 、tuple、dict、set、str等
- generator:包含生成器和带yield的generator function
- 可以直接作用于for循环的对象的为可迭代对象:Iterable
- 可以使用isinstance()判断一个对象是否是Iterable对象
- 不但可以作用于for循环,还可以被next()函数不断的调用并返回下一个值,直到抛出StopIteration错误无法继续返回下一个值
- 生成器都是Iterator对象,但list、dict、str虽然都是Iterable,不是Iterator
- 把list、dict、str等Iterable变成Iterator可以使用iter()函数:
- 总结:
- 凡是可以作用于for循环的对象的都是Iterable类型
- 凡是可作用于 next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
- Python的for循环本质上就是通过不断调用next()函数实现的