Hi! 大家好,我是Eric,这次教大家Python的迭代器(iterator)!
■ 迭代器(iterator)
■ 遍历列表
使用内建函数iter检查是否包含一个迭代器介面(iterator interface)iter([2, 4, 6, 8, 10])
这个iter物件是⼀个容器,让我们能够访问下⼀个物件(只要它是合法的)。可以通过内建的 next 函数检视:I = iter([2, 4, 6, 8, 10])print(next(I))print(next(I))
■ 不总是列表的列表:range()
range不是回传一个列表,而是回传一个特殊的range物件range(10)iter(range(10)) #range具有迭代器介面
迭代的好处是整个列表没有明确地完成建立,可以节省系统记忆体,如下我们不需要真的建立全部的1万亿个值N = 10 ** 12for i in range(N): if i >= 10: break print(i, end=', ') #Python的itertools套件中的count(),功能为无穷rangefrom itertools import count for i in count(): if i >= 10: break print(i, end=', ')
■ 实用迭代器介绍
enumerate。通常迭代过程需要迭代阵列的值,还要同步对索引进行追蹤L =[2, 4, 6, 8, 10]for i in range((L)): print(i, L(i))
以上可透过enumerate简洁化程式码for i,val in enumerate(L): print(i, val)
zip。另外一些情况,需要对多个列表进行迭代L = [2, 4, 6, 8, 10]R = [3, 6, 9, 12, 15]for lval, rval in zip(L, R): print(lval, rval) #任意数量的可迭代物件都可被连在⼀起,其中最短的那个列表将决定整个 zip 迭代器的长度。
map及filter# map 迭代器接受⼀个函式,并将它套用到迭代器中每⼀个值square = lambda x: x ** 2for val in map(square, range(10)): print(val, end=' ') # filter 迭代器看上去类似,但它只保留可以让过滤函式为真的值is_even = lambda x: x % 2 == 0for val in filter(is_even, range(10)): print(val, end=' ')
迭代器作为函式参数# *args 语法不仅仅适用于序列,同样适⽤于任意迭代器print(*range(10)) # 我们可以将之前的 map 例子用⼀个技巧整合进下面的函式呼叫print(*map(lambda x: x ** 2, range(10)))
使用上面的技巧,我们可以回答在 Python 初学者论坛上⼀个老生常谈的问题:为什么 Python中没有⼀个 unzip() 函式恰好执⾏ zip() 函数相反的操作呢?如果你把自己锁在⼀个漆黑的地⽅然后思考⼀会儿这个问题,你可能会意识到与 zip()相反的函式还是zip()!理解这个问题的关键在于 zip() 可以连结任意数量的迭代器或者序列。
L1 = (1, 2, 3, 4)L2 = ('a', 'b', 'c', 'd') z = zip(L1, L2)print(*z) z = zip(L1, L2)new_L1, new_L2 = zip(*z)print(new_L1, new_L2)
专用迭代器:itertools# itertools.permutations 函式在一个列表的全排(full permutation)中进行迭代from itertools import permutationsp = permutations(range(3))print(*p) # itertools.combinations 函式在⼀个列表中将所有不同的 N 组合中进行迭代from itertools import combinationsc = combinations(range(4), 2)print(*c) # product这个迭代器对两个或多个可迭代物件进⾏两两配对(实际上是求两个或多个集合的笛卡尔积(Cartesian Product)) ,最终产生⼀个集合进行迭代from itertools import productp = product('ab', range(3))print(*p)
■ Refer to《Python 旋风之旅,[正体中文]Will保哥》的第11章