在之前的章节中,我们介绍过Python可迭代对象、迭代器以及二者的区别联系,先来简单回顾一下:
迭代:通过for循环遍历取值的过程叫做迭代;
可迭代对象:能够通过for循环遍历取值的对象都是可迭代对象,如:字符串、列表、元组、字典、集合、range;
迭代器:既可以通过for循环遍历取值,也可以通过next()函数取值的对象就是迭代器对象;
迭代器和可迭代对象都可以用作for循环遍历;
迭代器一定是可迭代对象,因为同时实现了__iter__方法和__next__方法,可以通过next()方法获取下一个值,但是每个值只能获取一次;
但可迭代对象并不一定是迭代器,例如列表、字典、字符串,它们只实现了__iter__方法,如果想变成迭代器对象可以使用iter()进行转换;
只要可以用for循环遍历的都是可迭代对象,只要可以用next()函数遍历的都是迭代器对象;
可迭代对象是一次性将所有元素都加载到内存中,当可迭代对象长度较长时,会占用大量系统资源;而迭代器则是每次只获取一个、返回一个元素,不会造成资源浪费,在性能上优于可迭代对象;
itertools 模块标准化了一个快速、高效利用内存的核心工具集,这些工具本身或组合都很有用。它们一起形成了“迭代器代数”,这使得在纯Python中有可能创建简洁又高效的专用工具。
迭代器 | 实参 | 结果 | 示例 |
count() | start, [step] | start, start+step, start+2*step, ... | count(10) --> 10 11 12 13 14 ... |
cycle() | p | p0, p1, ... plast, p0, p1, ... | cycle('ABCD') --> A B C D A B C D ... |
repeat() | elem [,n] | elem, elem, elem, ... 重复无限次或n次 | repeat(10, 3) --> 10 10 10 |
使用count 打印1-100的所有奇数,最终结果会循环到101即停止:
import itertools'''无穷迭代器'''# count 打印1-100的所有奇数it = itertools.count(start=1, step=2)for i in it: print(i) if i > 100: break
使用cycle 对列表中的元素指定循环次数,因为列表有5个元素,所以for循环会在count为11时停止,此时列表循环2遍、循环到第3遍,也就是第一个元素1的时候停止。
# cycle 对列表中的元素指定循环次数testlist = [1, 2, 3, 4, 5]ic = itertools.cycle(testlist)count = 0for i in ic: print(i) count += 1 if count == 11: break'''12345123451'''
使用repeat, 指定列表的迭代次数,重复无限次或n次:
# repeat 指定列表的迭代次数testlist = [1, 2, 3, 4, 5]ir = itertools.repeat(object=testlist, times=3)for i in ir: print(i)'''[1, 2, 3, 4, 5][1, 2, 3, 4, 5][1, 2, 3, 4, 5]'''
迭代器 | 实参 | 结果 |
product() | p, q, ... [repeat=1] | 笛卡尔积,相当于嵌套的for循环 |
permutations() | p[, r] | 长度r元组,所有可能的排列,无重复元素 |
combinations() | p, r | 长度r元组,有序,无重复元素 |
combinations_with_replacement() | p, r | 长度r元组,有序,元素可重复 |
product('ABCD', repeat=2) | AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD | |
permutations('ABCD', 2) | AB AC AD BA BC BD CA CB CD DA DB DC | |
combinations('ABCD', 2) | AB AC AD BC BD CD | |
combinations_with_replacement('ABCD', 2) | AA AB AC AD BB BC BD CC CD DD |
列表testlist中有5个元素,元组dev_lan中有5个元素,所以它们的笛卡尔积一共会有25个结果:
# product 获取迭代对象的笛卡尔积testlist = [1, 2, 3, 4, 5]dev_lan = ('python', 'java', 'c++', 'go', 'ruby')ip = itertools.product(testlist, dev_lan)count = 0for p in ip: print(p) count += 1print(count)'''(1, 'python')(1, 'java')(1, 'c++')(1, 'go')(1, 'ruby')(2, 'python')(2, 'java')(2, 'c++')(2, 'go')(2, 'ruby')(3, 'python')(3, 'java')(3, 'c++')(3, 'go')(3, 'ruby')(4, 'python')(4, 'java')(4, 'c++')(4, 'go')(4, 'ruby')(5, 'python')(5, 'java')(5, 'c++')(5, 'go')(5, 'ruby')25'''
迭代对象dev_list中有5个元素,将其中的元素各自组合起来,生成一个指定长度的子序列。如果指定的子序列长度为1,那么就会有5种可能,如果每个子序列的长度为2就会有6种可能,如果长度为5,那么就只有一种可能,也就是和原来的dev_list一致,如果指定的长度超过现有的元素个数,则不会输出任何内容:
# combinations() 获取迭代对象内指定数量的元素组合,不重复dev_list = ('python', 'java', 'c++', 'go', 'ruby')cm = itertools.combinations(dev_list, 3)for c in cm: print(c)'''('python', 'java', 'c++')('python', 'java', 'go')('python', 'java', 'ruby')('python', 'c++', 'go')('python', 'c++', 'ruby')('python', 'go', 'ruby')('java', 'c++', 'go')('java', 'c++', 'ruby')('java', 'go', 'ruby')('c++', 'go', 'ruby')'''
# combinations_with_replacement() 获取迭代对象内指定数量的元素组合,包含重复项cwr = itertools.combinations_with_replacement(iterable=dev_list, r=3)for index, value in enumerate(cwr, 1): print(index, value)
当包含重复项的时候,一共有35种排列情况:
迭代器 | 实参 | 结果 | 示例 |
accumulate() | p [,func] | p0, p0+p1, p0+p1+p2, ... | accumulate([1,2,3,4,5]) --> 1 3 6 10 15 |
chain() | p, q, ... | p0, p1, ... plast, q0, q1, ... | chain('ABC', 'DEF') --> A B C D E F |
chain.from_iterable() | iterable -- 可迭代对象 | p0, p1, ... plast, q0, q1, ... | chain.from_iterable(['ABC', 'DEF']) --> A B C D E F |
compress() | data, selectors | (d[0] if s[0]), (d[1] if s[1]), ... | compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F |
dropwhile() | pred, seq | seq[n], seq[n+1], ... 从pred首次真值测试失败开始 | dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1 |
filterfalse() | pred, seq | seq中pred(x)为假值的元素,x是seq中的元素。 | filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8 |
groupby() | iterable[, key] | 根据key(v)值分组的迭代器 | |
islice() | seq, [start,] stop [, step] | seq[start:stop:step]中的元素 | islice('ABCDEFG', 2, None) --> C D E F G |
starmap() | func, seq | func(*seq[0]), func(*seq[1]), ... | starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000 |
takewhile() | pred, seq | seq[0], seq[1], ..., 直到pred真值测试失败 | takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4 |
tee() | it, n | it1, it2, ... itn 将一个迭代器拆分为n个迭代器 | |
zip_longest() | p, q, ... | (p[0], q[0]), (p[1], q[1]), ... | zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D- |
chain 多个可迭代对象组合起来进行迭代
创建一个迭代器,它首先返回第一个可迭代对象中所有元素,接着返回下一个可迭代对象中所有元素,直到耗尽所有可迭代对象中的元素。可将多个序列处理为单个序列。大致相当于:
def chain(*iterables): # chain('ABC', 'DEF') --> A B C D E F for it in iterables: for element in it: yield element
例如:
# chain 多个可迭代对象组合起来进行迭代testlist = [1, 2, 3, 4, 5]dev_lan = ('python', 'java', 'c++', 'go', 'ruby')itc = itertools.chain(testlist, dev_lan)for i in itc: print(i)'''12345pythonjavac++goruby'''
创建一个迭代器,它返回 data 中经 selectors 真值测试为 True 的元素。迭代器在两者较短的长度处停止。大致相当于:
def compress(data, selectors): # compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F return (d for d, s in zip(data, selectors) if s)
例如:迭代对象true_list中的元素,1表示真,0表示假,所以第1、3、5个元素就是真,2、4元素为假,也就会返回data中第1、3、5个元素,第2、4个元素不返回:
# itertools.compress(data, selectors) 返回与真选择器元素相对应的数据元素true_list = [1, 0, 1, 0, 1]cc = itertools.compress(data=['java', 'ruby', 'javascript', 'html', 'python'], selectors=true_list)for c in cc: print(c)'''javajavascriptpython'''
创建一个迭代器,如果 predicate 为true,迭代器丢弃这些元素,然后返回其他元素。注意,迭代器在 predicate 首次为false之前不会产生任何输出,所以可能需要一定长度的启动时间。大致相当于:
def dropwhile(predicate, iterable): # dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1 iterable = iter(iterable) for x in iterable: if not predicate(x): yield x break for x in iterable: yield x
返回满足首次指定条件的元素之后的所有元素,这句话听起来可能比较拗口,下面我们通过一个例子来解释,例如:迭代对象dev_list中有多个类型的元素,有整型、字符串型、列表型、元组型、浮点型。先通过匿名表达式lambda x: not isinstance(x, Iterable)来判断哪些元素不是可迭代对象,从列表元素可以看出:
'9999' 可迭代对象
888 不可迭代对象
'python' 可迭代对象
(88, 77) 可迭代对象
[1, 2, 3] 可迭代对象
0.999 不可迭代对象
使用dropwhile()方法对dev_list进行迭代判断,当找到第一个条件为True的选项(也就是第一个不是可迭代对象的元素)时,就停止,然后返回这个元素之后的所有元素。所以:'9999'元素是可迭代对象、结果为False,继续查找,888元素不是可迭代对象,满足条件,结果为True,停止查找,然后返回888这个元素后的所有元素:
# itertools.dropwhile(predicate, iterable) 返回满足首次指定条件的元素之后的所有元素from collections.abc import Iterabledev_list = ['9999', 888, 'python', (88, 77), [1, 2, 3], 0.999]iw = itertools.dropwhile(lambda x: not isinstance(x, Iterable), dev_list)for i in iw: print(i)'''python(88, 77)[1, 2, 3]0.999'''
联系客服