-
六、迭代器和生成器
1. 迭代
在 Python 中,给定一个 list 或 tuple,我们可以通过 for 循环来遍历这个 list 或 tuple ,这种遍历就是迭代。
但Python 的
for
循环抽象程度要高于 Java 的for
循环, 因为 Python 的for
循环不仅可以用在 list 或tuple 上,还可以作用在其他可迭代对象上。也就是说,只要是可迭代的对象,无论有没有下标,都是可以迭代的,迭代是 Python 最强大的功能之一,是访问集合元素的一种方式。
# 遍历tuple tuple = (99, 'hello', True) for t in tuple: print(t) # 遍历字符串 for x in 'hello': print(x, end='------')
打印结果如下:
99 hello True h------e------l------l------o------
2. 迭代器
- 迭代器是一个可以记住遍历的位置的对象
- 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。
- 迭代器只能往前不会后退。
- 迭代器有两个基本的方法:iter() 和 next(),且字符串,列表或元组对象都可用于创建迭代器,迭代器对象可以使用常规 for 语句进行遍历,也可以使用 next() 函数来遍历。
# 迭代器 # 1. 字符串创建迭代器 str1 = 'cold_boy' iter_str = iter(str1) # 2. list创建迭代器 list1 = [1, 2, 3, 56, 66] iter_list = iter(list1) # 3.tuple创建迭代器 tuple1 = (11, 'kkk', True) iter_tuple = iter(tuple1) # for 遍历 for s in iter_str: print(s, end='------') # 使用next遍历 print() print(next(iter_tuple)) print(next(iter_tuple)) print(next(iter_tuple))
执行结果:
3. 切片
对于取list或tuple取指定索引范围的操作,用循环十分繁琐,因此,Python提供了切片(Slice)操作符,能大大简化这种操作。
# 1. 取list前三个值 list = list(range(30)) l1 = list[0:3] print(l1) # 2. 从第一个索引开始的情况,0可省略 l2 = list[:3] print(l2) # 3. 用负数作为索引(最后一个数是-1) l3 = list[-5:] print(l3) # 4. 取索引为10-15的值 l4 = list[10:15] print(l4) # 5. 前10个数,每隔两个取一次 l5 = list[:10:2] print(l5) # 6. 所有数,每隔5个取一次 l6 = list[::5] print(l6) # 7. 复制一个list l7 = list[:] print(l7) # tuple、字符串也可以进行切片操作
执行结果:
4. list生成式
- 利用
range(x,y)
创建list
list1=list ( range (1,31) ) print(list1)
执行结果:
[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]
打印九九乘法表:
print('\n'.join([' '.join ('%dx%d=%2d' % (x,y,x*y) for x in range(1,y+1)) for y in range(1,10)]))
执行结果:
- list生成式的创建
list 生成式的语法为:
[expr for iter_var in iterable] [expr for iter_var in iterable if cond_expr]
第一种语法:首先迭代 iterable 里所有内容,每一次迭代,都把 iterable 里相应内容放到iter_var 中,再在表达式中应用该 iter_var 的内容,最后用表达式的计算值生成一个列表。
第二种语法:加入了判断语句,只有满足条件的内容才把 iterable 里相应内容放到 iter_var 中,再在表达式中应用该 iter_var 的内容,最后用表达式的计算值生成一个列表。
# 第一种:list的元素为遍历range函数的值加1得来 list1 = [x + 1 for x in range(30)] print(list1) # 第二种:list的元素为遍历range函数的值加1得来,并且遍历的值必须为偶数 list2 = [x + 1 for x in range(30) if x % 2 == 0] print(list2)
执行结果:
5. 生成器
如果列表元素可以按照某种算法推算出来,这种边循环边计算的机制,成为生成器:generator
- 生成器的创建
最简单最简单的方法就是把一个列表生成式的
[]
改成()
# 生成器创建 gen = (x * x for x in range(10)) print(gen)
执行结果:
<generator object <genexpr> at 0x000001A77D599C10>
创建 List 和 generator 的区别仅在于最外层的
[]
和()
。但是生成器并不真正创建数字列表, 而是返回一个生成器,这个生成器在每次计算出一个条目后,把这个条目“产生” ( yield ) 出来。
生成器表达式使用了“惰性计算” ( lazy evaluation,也有翻译为“延迟求值”,我以为这种按需调用 call by need 的方式翻译为惰性更好一些),只有在检索时才被赋值( evaluated ),所以在列表比较长的情况下使用内存上更有效。
- 遍历生成器的元素
for
循环和next()
函数都可以遍历生成器# 遍历生成器 gen = (x * x for x in range(10)) for g in gen: print(g, end='-')
执行结果:
0-1-4-9-16-25-36-49-64-81-
- 以函数的形式实现生成器
生成器也是一种迭代器,但是你只能对其迭代一次。 这是因为它们并没有把所有的值存在内存中,而是在运行时生成值。你通过遍历来使用它们,要么用一个“for”循环,要么将它们传递给任意可以进行迭代的函数和结构。
实现一个简单的函数生成器:
def func(): for i in range(100): yield i print(func())
执行结果:
` yield `关键字:
yield
相当等于return
,会将程序的某个值返回,返回后程序就不会再继续运行下去了- 有
yield
关键字的函数并不会真正执行,而是会得到一个函数生成器 - 可以使用迭代或者next()方法执行
yield
的生成器
用函数实现一个计算斐波那契数列的生成器:
生成器最好的使用场景应该是:你不想同一时间将所有计算出来的大量结果集分配到内存当中,特别是结果集里还包含循环。使用生成器的话可以一边计算一边生成数据,减少不必要的资源消耗
# 以函数实现一个斐波那切数列的生成器 def fibon(n): a = b = 1 for i in range(n): yield a a, b = b, a + b for x in fibon(100000): print(x)
打印杨辉三角:
def triangles(n): # 杨辉三角形 L = [1] while True: yield L L.append(0) L = [L[i - 1] + L[i] for i in range(len(L))] n = 0 for t in triangles(10): # 直接修改函数名即可运行 print(t) n = n + 1 if n == 10: break
执行结果:
6.
sort()
和sorted()
sort()
对列表中元素进行排序,默认是直接比较列表中元素的大小,但
sort()
可以接受一个关键字参数key
,key
需要一个函数作为参数,每一个列表中的元素都会作为参数来调用函数,并使用函数的返回值来比较元素大小list = ['bbb', 'aa', 'eeeee', 'vvvvvvvv', 'llll'] list.sort(key=len) #此处的len是获取长度的函数len() print(list)
sorted()
sorted()
函数的用法与sort()
基本一致,但sorted()
可以对任意序列进行排序- 使用
sorted()
排序不会对原序列产生影响,而是返回一个新的序列
list = ['bbb', 'aa', 'eeeee', 'vvvvvvvv', 'llll'] list2 = sorted(list,key=len) print(list2)