Python3中实现了不少生成器函数,本篇主要介绍built-in、itertools、functools模块中的生成器。python
本类生成器函数将iterable对象做为参数,在不改变该iterable对象的条件下,返回iterable子集的生成器对象。segmentfault
iterable的每个元素会传入predicate函数中判断是否为True,该生成器会返回全部返回为True的元素组成的生成器对象。异步
def is_vowel(c): return c.lower() in 'aeiou' word = 'abcdefghijk' print(list(filter(is_vowel, word))) ## output: ['a', 'e', 'i']
filter会过滤掉word中全部非元音字母,返回符合元素组成的生成器对象。
注意:经过list(generator)能够将生成器对象转换为列表,但若是是无限生成器list将会产生大量元素致使出错。
filter函数等同于下面的生成器表达式用法。函数
(item for item in iterable if function(item))
若是filter的第一个参数为None,则不过滤返回所有,等同于下面的生成器表达式用法。工具
(item for item in iterable if item)
该函数和filter相似,区别是过滤掉predicate返回True的元素。ui
print(list(itertools.filterfalse(is_vowel, word))) ## output: ['b', 'c', 'd', 'f', 'g', 'h', 'j', 'k']
该函数连续迭代iterable对象中的元素,并用predicate函数判断,若predicate返回为True,将不断产出该元素,直到predicate返回False,过滤了iterable后面不符合的元素。code
print(list(itertools.takewhile(is_vowel, word))) ## output: ['a']
该函数与itertools.takewhile相反,过滤了iterable对象前面符合predicate返回True的元素,保留后面的子集。对象
print(list(itertools.dropwhile(is_vowel, word))) ## output: ['b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']
该函数中的selectors也是一个迭代对象,compress根绝selectors中的值(0/1或是True/False)判断是否过滤iterable中的元素。排序
print(list(itertools.compress(word, [1, 0, 1, 0]))) ## output: ['a', 'c']
若是selectors长度不够,则iterable后面的对象所有被过滤掉。索引
根据传入参数的个数不一样,该函数另外一种写法是itertools.islice(iterable, start, stop[, step]),islice函数相似python中的分片操做:list[start:stop:step]。
print(list(itertools.islice(word, 4))) ## output: ['a', 'b', 'c', 'd'] print(list(itertools.islice(word, 4, 8))) ## output: ['e', 'f', 'g', 'h'] print(list(itertools.islice(word, 4, 8, 2))) ## output: ['e', 'g']
该类生成器主要对于传入的一个或多个迭代对象中的每个元素进行操做,返回映射后的生成器对象。
map是Python中经常使用的原生生成器,将迭代对象中的每个元素传入func进行映射返回新的迭代对象。若是有n个iterable对象,则func的参数则为n个,后面的timeout和chunksize参数涉及到异步,本篇将不阐述。
print(list(map(lambda x: x.upper(), word))) print([x.upper() for x in word]) ## output: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K']
上面第一行中的map将word中的每一个元素转换为大写,和第二行中的列表生成式用法类似。
print(list(map(lambda x, y: (x, y), word, word))) print(list(zip(word, word))) ## output: [('a', 'a'), ('b', 'b'), ('c', 'c') ... ('k', 'k')]
当有两个iterable传入时,func将须要处理传入的两个参数,第一行的用法和zip函数的做用类似。
当iterable中的元素也是个迭代对象时,若是使用map函数,须要在函数内部实现解压操做获取到单个元素,而startmap将iterable中的元素按function(*item)方式传入,咱们能够在定义function的参数时完成解压操做。举例,若是想输入序列[(2,5), (3,2), (10,3)]来获得一个每一个元组元素的和的序列[7, 5, 13], 若使用map方法,fun函数将会复杂,而使用startmap则只须要传递一个add函数做为startmap参数,元组解压后的两个值将传入add函数做为参数。
from operator import add print(list(map(lambda x: add(x[0], x[1]), [(2, 5), (3, 2), (10, 3)]))) print(list(itertools.starmap(add, [(2, 5), (3, 2), (10, 3)]))) ## output: [7, 5, 13]
enumerate函数也是常见的生成器函数,它的主要用法是提供for-in循环中的索引。若设置start参数,索引将从start值开始逐1增长。
for i, c in enumerate(word, 2): print(i, c)
accumulate函数将经过func函数完成逐步累加操做,默认func为operator.add。下面用例子进行说明。
sample = [1, 2, 3, 4, 5] print(list(itertools.accumulate(sample))) ## output: [1, 3, 6, 10, 15] print(list(itertools.accumulate(sample, mul))) ## output: [1, 2, 6, 24, 120] print(list(itertools.accumulate(sample, mul))) ## output: [1, 2, 6, 24, 120] print(list(itertools.accumulate(sample, min))) ## output: [1, 1, 1, 1, 1] print(list(itertools.accumulate(sample, max))) ## output: [1, 2, 3, 4, 5] print(list(itertools.starmap(lambda x, y: y/x, enumerate(itertools.accumulate(sample), 1)))) ## output: [1.0, 1.5, 2.0, 2.5, 3.0]
合并生成器接收多个可迭代对象参数,将他们组合后返回新的生成器对象。
chain生成器函数接收多个可迭代对象参数,将他们按顺序组合成新的生成器对象返回。
print(list(itertools.chain(range(3), range(3, 7)))) ## output: [0, 1, 2, 3, 4, 5, 6]
chain.from_iterable函数接收一个元素为可迭对象的可迭代对象,将该全部可迭代的元素拆开,从新按顺序组合成一个新的生成器,新的生成器产出的元素为iterable参数某个元素的解压,chain.from_iterable功能更像是逐层解压迭代对象。
a, b = [1,2], [3,4] iterable= [[a,b],[a,b]] print(iterable) new_iterable = list(itertools.chain.from_iterable(iterable)) print(new_iterable) print(list(itertools.chain.from_iterable(new_iterable))) ## output: ## [[[1, 2], [3, 4]], [[1, 2], [3, 4]]] ## [[1, 2], [3, 4], [1, 2], [3, 4]] ## [1, 2, 3, 4, 1, 2, 3, 4]
zip函数接收多个iterable参数,并提取每一个iterable元素组成元组,返回这些元组组成的生成器对象。
iterable1 = 'abcd' iterable2 = [1, 2, 3] iterable3 = [10, 20, 30, 40] print(list(zip(iterable1, iterable2, iterable3))) ## output: ## [('a', 1, 10), ('b', 2, 20), ('c', 3, 30)]
若是多个iterable元素个数不一致,zip会在最短的iterable耗尽后中止。
咱们能够经过zip函数生成一个字典对象
keys = 'abc' values = [1, 2, 3] print(dict(zip(keys, values))) ## output: {'a': 1, 'b': 2, 'c': 3}
zip_longes函数做用和zip相似,在zip中若是某个iterable对象耗尽,生成器将就此中止,而zip_longest函数将为耗尽的iterable补充fillvalue值。
iterable1 = 'abcd' iterable2 = [1, 2, 3] iterable3 = [10, 20, 30, 40] print(list(itertools.zip_longest(iterable1, iterable2, iterable3, fillvalue=0))) ## output: [('a', 1, 10), ('b', 2, 20), ('c', 3, 30), ('d', 0, 40)]
product函数计算全部iterable的笛卡尔积,它像是生成器表达式中处理嵌套循环的步骤,product(a, b)能够等同于((x, y) for x in a for y in b)。
repeat至关于扩展了iterables, product(a, b, repeat=2)至关于product(a, b, a, b)
a = (0, 1) b = (2, 3) print(list(itertools.product(a, b))) print(list(itertools.product(a, repeat=2))) ## output: ## [(0, 2), (0, 3), (1, 2), (1, 3)] ## [(0, 0), (0, 1), (1, 0), (1, 1)]
扩展生成器将传进的单一对象进行扩展,生成更多元素组成的生成器对象。
repeat函数能够接收一个对象(能够不是可迭代对象), 根据非必选参数times,生成元素个数为times的生成器,若是不提供times参数,将生成无限生成器。
print(list(itertools.repeat(1, 3))) print(list(itertools.repeat((1, 2), 3))) print(list(zip(range(1, 4), itertools.repeat('a')))) print([1, 2] * 3) """output: [1, 1, 1] [(1, 2), (1, 2), (1, 2)] [(1, 'a'), (2, 'a'), (3, 'a')] [1, 2, 1, 2, 1, 2] """
注意repeat()和列表乘法的区别,经过上文提到的itertools.chain.from_iterable函数结合repeat函数能够实现列表乘法。
lst = [1, 2, 3] g = itertools.repeat(lst, 3) print(list(itertools.chain.from_iterable(g))) print(lst * 3) """output [1, 2, 3, 1, 2, 3, 1, 2, 3] [1, 2, 3, 1, 2, 3, 1, 2, 3] """
cycle函数将传进的iterable可迭代对象首尾相连造成循环,生成无限生成器。
# cycle('ABCD') --> A B C D A B C D A B C D ...
计数器函数,start和step参数能够为小数,直接看例子。
g = itertools.count(1.2, 2.5) print(next(g)) print(next(g)) print(next(g)) """output: 1.2 3.7 6.2 """
上文提到的enumerate生成器函数能够经过map和count来实现。
for i, v in map(lambda x, y: (x, y), itertools.count(), range(3, 10)): print(i, v)
咱们能够经过调整count函数让索引i的值更加灵活。
Python中的range(start, stop[, step])函数能够生成一个序列,可是要求输入参数必须为整数,能够经过count函数实现一个能够接收小数的新range。
def range_new(start, stop, step): for i in itertools.count(start, step): if i >= stop: break yield i print(list(range_new(1, 5.5, 1.5))) ## output: [1, 2.5, 4.0]
如下三个函数能够实现迭代对象的排列组合
itertools.combinations(iterable, r)
非重复组合
print(list(itertools.combinations('ABC', 1))) print(list(itertools.combinations('ABC', 2))) print(list(itertools.combinations('ABC', 3))) """output: [('A',), ('B',), ('C',)] [('A', 'B'), ('A', 'C'), ('B', 'C')] [('A', 'B', 'C')] """
itertools.combinations_with_replacement(iterable, r)
重复组合
print(list(itertools.combinations_with_replacement('ABC', 1))) print(list(itertools.combinations_with_replacement('ABC', 2))) print(list(itertools.combinations_with_replacement('ABC', 3))) """output: [('A',), ('B',), ('C',)] [('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'B'), ('B', 'C'), ('C', 'C')] [('A', 'A', 'A'), ('A', 'A', 'B'), ('A', 'A', 'C'), ('A', 'B', 'B'), ('A', 'B', 'C'), ('A', 'C', 'C'), ('B', 'B', 'B'), ('B', 'B', 'C'), ('B', 'C', 'C'), ('C', 'C', 'C')] """
itertools.permutations(iterable, r=None)
全排列
print(list(itertools.permutations('ABC', 1))) print(list(itertools.permutations('ABC', 2))) print(list(itertools.permutations('ABC', 3))) """output: [('A',), ('B',), ('C',)] [('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('C', 'A'), ('C', 'B')] [('A', 'B', 'C'), ('A', 'C', 'B'), ('B', 'A', 'C'), ('B', 'C', 'A'), ('C', 'A', 'B'), ('C', 'B', 'A')] """
对比itertools.product(*iterables, repeat=1)函数
print(list(itertools.product('ABC', repeat=1))) print(list(itertools.product('ABC', repeat=2))) """output: [('A',), ('B',), ('C',)] [('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'B'), ('B', 'C'), ('C', 'A'), ('C', 'B'), ('C', 'C')] """
此类生成器将传入的可迭代对象通过整理后,以生成器的形式所有返回。
groupby生成器能够根据key,将iterable分组,返回的生成器的元素为(key, iterable)的元组形式。扫描整个序列而且查找连续相同值(或者根据指定 key 函数返回值相同)的元素序列。 在每次迭代的时候,它会返回一个值和一个迭代器对象, 这个迭代器对象能够生成元素值所有等于上面那个值的组中全部对象。
g = itertools.groupby('LLLLAAGGG') for char, group in g: print(char, '->', list(group)) """output: L -> ['L', 'L', 'L', 'L'] A -> ['A', 'A'] G -> ['G', 'G', 'G'] """ rows = [ {'address': '5412 N CLARK', 'date': '07/01/2012'}, {'address': '5148 N CLARK', 'date': '07/04/2012'}, {'address': '5800 E 58TH', 'date': '07/02/2012'}, {'address': '2122 N CLARK', 'date': '07/03/2012'}, {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'}, {'address': '1060 W ADDISON', 'date': '07/02/2012'}, {'address': '4801 N BROADWAY', 'date': '07/01/2012'}, {'address': '1039 W GRANVILLE', 'date': '07/04/2012'}, ] rows.sort(key=itemgetter('date')) g = itertools.groupby(rows, itemgetter('date')) for char, group in g: print(char, '->', list(group)) """output: 07/01/2012 -> [{'address': '5412 N CLARK', 'date': '07/01/2012'}, {'address': '4801 N BROADWAY', 'date': '07/01/2012'}] 07/02/2012 -> [{'address': '5800 E 58TH', 'date': '07/02/2012'}, {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'}, {'address': '1060 W ADDISON', 'date': '07/02/2012'}] 07/03/2012 -> [{'address': '2122 N CLARK', 'date': '07/03/2012'}] 07/04/2012 -> [{'address': '5148 N CLARK', 'date': '07/04/2012'}, {'address': '1039 W GRANVILLE', 'date': '07/04/2012'}] """
groupby() 仅仅检查连续的元素,所以在调用以前须要根据指定的字段将数据排序。
reversed函数接收一个序列(实现sequence相关协议,已知长度)
print(list(reversed(range(5)))) ## output: [4, 3, 2, 1, 0]
tee函数返回单个iterable对象的n个独立迭代器
g1, g2 = itertools.tee('ABC') print(next(g1), next(g2)) print(next(g1), next(g2)) print(list(zip(*itertools.tee('ABC')))) """output A A B B [('A', 'A'), ('B', 'B'), ('C', 'C')] """
接收一个迭代对象,处理只返回一个单一值。
function参数是一个接收两个参数的函数function(x, y),reduce函数将上一次function获得的返回值做为参数x,将iterable的下一次迭代值做为参数y传进function计算,初始时x的值为initializer值(若initializer为None,初始值则为iterable的第一个元素值)。循环直到iterable耗尽返回最终值。
reduce的基本实现大概为一下代码:
def reduce(function, iterable, initializer=None): it = iter(iterable) if initializer is None: value = next(it) else: value = initializer for element in it: value = function(value, element) return value
print(functools.reduce(add, [1, 2, 3, 4, 5])) ## output: 15
经常使用的min和max函数均可以用reduce实现
def min_reduce(iterable): return functools.reduce(lambda x, y: x if x < y else y, iterable) def max_reduce(iterable): return functools.reduce(lambda x, y: x if x > y else y, iterable) print(min_reduce([4, 6, 6, 78])) print(max_reduce([4, 6, 6, 78])) """output 4 78 """
除此以外any和all函数原理也是相似,再也不阐述。
本篇按照分类介绍了python库中的一些经常使用的生成器,能够经过不一样场景选择不一样的生成器工具,将它们组合灵活运用。