本文是学习齐老师的《python全栈工程师》课程的笔记,欢迎学习交流。同时感谢齐老师的精彩传授!
一、课程目标
- 理解迭代器的含义和应用
- 理解生成器的含义和应用
二、详情解读
01.迭代器:
迭代(iteration): 迭代是重复反馈过程的活动,其目的通常是为了接近并到达所需的目标或结果。每一次对过程的重复被称为一次”迭代“,而每一次迭代得到的结果会被用来作为下一次迭代的初始值。
典型应用:”牛顿法“求根:
x
m
−
a
=
0
设
:
f
(
x
)
=
x
m
−
a
,
f
′
(
x
)
=
m
x
m
−
1
x
n
+
1
=
x
n
−
f
(
x
n
)
f
′
(
x
n
)
则
x
n
+
1
不
断
逼
近
a
的
m
次
方
根
x^m - a = 0 \\ 设:f(x) = x^m - a, \\ f{'}(x) = mx^{m-1}\\ x_{n+1} = x_n - \frac{f(x_n)}{f{'}(x_n)}\\ 则x_{n+1}不断逼近a的m次方根
xm−a=0设:f(x)=xm−a,f′(x)=mxm−1xn+1=xn−f′(xn)f(xn)则xn+1不断逼近a的m次方根
value = 23
epsilon = 0.001
result = value / 2
while abs(result * result - value) >= epsilon:
result = result - ((result*result - value) / ( 2 * result))
print('The square root of {0} is about {1}'.format(value, result))
import math
print(math.sqrt(23))
可迭代对象: 是指能够逐一返回其成员的对象。主要包括:所有序列类型(例如list,str 和 tuple)、某些非序列类型例如 dict和文件对象、还有定义了__iter__()方法或是实现了Sequence 语义的__getitem__()方法的任意自定义类对象。一般用__iter__判断是否是可迭代对象。
可迭代对象用于for循环以及某些对象的参数比例如map等。
print(hasattr(list, '__iter__')) # True
r = range(0, 10)
print(hasattr(r, '__iter__')) # True
迭代器(iterator):
- 用来表示一连串数据流的对象。重复调用迭代器的__next__()方法(或将其传给内置函数 next())将逐个返回流中的项。当没有数据可用时则将引发StopIteration异常。
- 迭代器必须具有__iter__()方法用来返回该迭代器对象自身,因此迭代器必定也是可迭代对象。
- 使用内置函数iter()创建迭代器对象。
- 判断:iter__和__next
lst = [1,2,3]
print(hasattr(lst, '__iter__')) # True
print(hasattr(lst, '__next__')) # False 说明列表是可迭代的,但不是迭代器
iter_lst = iter(lst) # 创建迭代器对象
print(hasattr(iter_lst, '__iter__')) # True
print(hasattr(iter_lst, '__next__')) # True
print(iter_lst.__next__()) # 1
print(iter_lst.__next__()) # 2
print(iter_lst.__next__()) # 3
print(iter_lst.__next__()) # 报 StopIteration异常
# 注意遍历迭代器时,数据流是否已经读取完毕
for i in iter_lst:
# 此处打印为空,因为上面的__next__()操作,已经将数据流读取完毕了,相当于指针已经指到最后了
# 这里不报错是因为for循环自动捕获并处理了stopIteration异常了
print(i)
# 为了解决上面提到的问题,简单粗暴的方法是重新创建一个迭代器对象
iter_lst = iter(lst)
for i int iter_lst:
print(i) # 1 2 3
迭代器的执行过程:
补充for循环的发生过程
例题1:
编写斐波那契数列的迭代器对象。
class Fibs:
def __init__(self, max):
self.max = max
self.a = 0
self.b = 1
def __iter__(self):
return self
def __next__(self):
fib = self.a
if fib > self.max:
raise StopIteration
self.a, self.b = self.b, self.a + self.b
return fib
fibs = Fibs(100000)
lst = [fibs.__next__() for i in range(10)]
print(lst) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
# 还有一种创建迭代器的方法
import itertools
c = itertools.count(start=3) # 从3 开始到无限大
print(next(c)) # 3
printable(next(c)) # 4
colors = itertools.cycle(['red', 'yellow', 'blue'])
print(next(colors)) # red
print(next(colors)) # yellow
print(next(colors)) # blue
print(next(colors)) # red 以此循环下去
02.生成器:
生成器(generator): 类似普通函数,不同点在于其包含yield表达式,生成器也是迭代器。
# 普通函数
def r_return(n):
while n > 0:
print('before return')
return n
n -= 1
print('after return')
re = r_return(3) # before return
print(re) # 3
# 生成器
def y_yield(n):
while n > 0:
print('before yield')
yield n
n -= 1
print('after yield')
yy = y_yield(3) # 创建一个迭代器对象(也是生成器)
print(yy.__next__()) # before yield 3
print(yy.__next__()) # after yield before yield 2
print(yy.__next__()) # after yield before yield 1
print(yy.__next__()) # 先打印 after yield,然后报错,因为指针已经移动到迭代器的最尾端了
例题2:
编写斐波那契数列的生成器函数。
def fibs():
prev, curr = 0, 1
while True:
yield prev
prev, curr = curr, prev + curr
import itertools
print(list(itertools.islice(fibs(), 10))) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
生成器解析:
# 列表解析:
lst = [x ** 2 for x in range(10)]
print(lst) # [0,1,4,9,16,25,36,49,64,81]
# 生成器解析
gt = (x ** 2 for x in range(10))
print(gt) # <generator object <genexpr> at 0x105e9ee60>
三、课程小结
- 学习了迭代器
- 学习了生成器
四、作业
内置函数range 的参数必须是整数。请编写一个生成器函数,以浮点数为参数(开始值,结束值,步长)生成某范围的序列。
def y_range(start, end, step=1):
while start < end:
yield start
start = start + step
import itertools
start = 0.2
end = 11
step = 2.5
n = round((end-start)/step) + 1
lst = list(itertools.islice(y_range(start, end, step), n))
print(lst) # [0.2, 2.7, 5.2, 7.7, 10.2]