迭代器和生成器
1. 迭代
1.1 迭代的定义
在 Python 中,给定一个 list 或 tuple,我们可以通过 for 循环来遍历这个 list 或 tuple ,这种遍历就是迭代。
迭代案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
for char in 'liangdianshui' : print ( char , end = ' ' )
print('\n')
list1 = [1,2,3,4,5] for num1 in list1 : print ( num1 , end = ' ' )
print('\n')
dict1 = {'name':'两点水','age':'23','sex':'男'}
for key in dict1 : print ( key , end = ' ' )
print('\n')
for value in dict1.values() : print ( value , end = ' ' )
print ('\n')
for x , y in [ (1,'a') , (2,'b') , (3,'c') ] : print ( x , y )
|
1.2 迭代器
- 迭代器 是一个可以记住遍历的位置的对象,从集合的第一个元素开始访问,直到所有的元素被访问完结束.
- 迭代器有两个基本的方法:
iter()
和 next()
, 且 字符串,列表 或 元组 对象都可用于创建迭代器, - 迭代器对象可以使用常规
for
语句进行遍历,也可以使用 next()
函数来遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| str1 = 'liangdianshui' iter1 = iter (str1)
list1 = [1,2,3,4] iter2 = iter (list1)
tuple1 = (1,2,3,4) iter3 = iter (tuple1)
for x in iter1 : print (x, end=' ')
while True : try : print (next (iter3)) except StopIteration : break
|
2. list 生成式(列表生成式)
2.1 创建 list
1 2 3 4
| list1 = list(range(1,31))
print(list1)
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| print('\n'.join([' '.join(f'{x}*{y}={x * y}' for x in range(1, y+1)) for y in range(1, 10)]))
输出结果: 1*1=1 2*1=2 2*2=4 3*1=3 3*2=6 3*3=9 4*1=4 4*2=8 4*3=12 4*4=16 5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
|
2.2 列表生成式
list 生成式的语法格式:
结果 for 元素 in 集合
- 把集合中的元素依次提取出来, 然后在表达式中应用元素, 最后把表达式的结果添加到结果中
结果 for 元素 in 集合 if 筛选条件
- 把条件成立的元素从集合中提取出来, 然后在表达式中应用元素, 最后把表达式的结果添加到结果中
1 2 3 4 5
| list1=[x * x for x in range(1, 11)] print(list1)
list1= [x * x for x in range(1, 11) if x % 2 == 0] print(list1)
|
1 2 3 4
| list1 = [(x, y) for x in range(2) for y in range(3)] print(list1)
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]
|
3. 生成器(generator
)
在 Python 中,这种一边循环一边计算的机制,称为生成器:generator
在 Python 中,使用了 yield 的函数被称为生成器(generator)
在调用生成器运行的过程中,每次遇到 yield
时函数会暂停并保存当前所有的运行信息,返回 yield 的值。并在下一次执行 next()方法时从当前位置继续运行
3.1 生成器创建
生成器创建 最简单的方法就是把一个列表生成式的 []
改成 ()
1 2 3 4 5 6
| gen= (x * x for x in range(10)) print(gen)
输出的结果: <generator object <genexpr> at 0x0000000002734A40>
|
创建 List
和 generator
的区别仅在于最外层的 []
和 ()
。
生成器并不真正创建数字列表,而是返回一个生成器
这个生成器在每次计算出一个条目后,把这个条目产生(yield)
出来。
生成器表达式使用了 惰性计算 (lazy evaluation,也有翻译为“延迟求值”,我以为这种按需调用 call by need 的方式翻译为惰性更好一些),只有在检索时才被赋值(evaluated
),所以在列表比较长的情况下使用内存上更有效。
3.2 遍历生成器的元素
1 2 3 4 5 6 7 8 9 10
| gen = (x*x for x in range(10))
for i in gen: print(i, end=' ')
while True: try: print(next(gen), end=' ') except StopIteration: break
|
3.3 以函数的形式实现生成器
1 2 3 4 5 6 7 8 9 10 11 12
| def odd(): print('step 1') yield 1 print('step 2') yield 3 print('step 3') yield 5
o = odd() print(next(o)) print(next(o)) print(next(o))
|
可以看到,odd 不是普通函数,而是 generator,在执行过程中,遇到 yield 就中断,下次又继续执行。
执行 3 次 yield 后,已经没有 yield 可以执行了,如果你继续打印 print(next(o)),就会报错的。
所以通常在 generator 函数中都要对错误进行捕获。
1 2 3 4 5 6 7 8 9 10
| def fibon(n): a = b = 1 for i in range(n): yield a a, b = b, a + b
for x in fibon(10): print(x , end = ' ')
|
3.4 打印杨辉三角
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| def triangles(): lists = [1] while True: yield lists lists.append(0) lists = [lists[i - 1] + lists[i] for i in range(len(lists))]
n = 0 for t in triangles(): print(t) n = n + 1 if n == 5: break
输出结果: [1] [1, 1] [1, 2, 1] [1, 3, 3, 1] [1, 4, 6, 4, 1]
|
4. 迭代器和生成器结合
4.1 反向迭代
反向迭代仅仅当对象的大小可 预先确定
或者对象实现了 __reversed__()
的特殊方法时才能生效。
如果两者都不符合,那你必须先将对象转换为一个列表才行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Countdown: def __init__(self, start): self.start = start
def __iter__(self): n = self.start while n > 0: yield n n -= 1
def __reversed__(self): n = 1 while n <= self.start: yield n n += 1
for rr in reversed(Countdown(10)): print(rr, end=' ')
for rr in Countdown(10): print(rr, end=' ')
|
4.2 同时迭代多个序列
zip()
函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
1 2 3 4 5
| names = ['laingdianshui', 'twowater', '两点水'] ages = [18, 19, 20]
for name, age in zip(names, ages): print(name, age, end=', ')
|
利用zip()
函数,我们还可把一个 key 列表和一个 value 列表生成一个 dict(字典)
1 2 3 4 5 6
| names = ['laingdianshui', 'twowater', '两点水'] ages = [18, 19, 20]
dict1 = dict(zip(names, ages))
print(dict1)
|