ITPub博客

首页 > 应用开发 > > Python 标准库 itertools

Python 标准库 itertools

作者:youou 时间:2019-09-27 09:55:09 0 删除 编辑

狮范课 


为高效循环而创建迭代器的函数

无穷迭代器

itertools.count(start=0, step=1):创建一个迭代器,它从 start 值开始,返回均匀间隔的值。常用于 map() 中的实参来生成连续的数据点。此外,还用于 zip() 来添加序列号。大致相当于:

def count(start=0, step=1):

n = start # 起始点

while True: # 无限循环

yield n

n += step # 步进

itertools.cycle(iterable):创建一个迭代器,返回 iterable 中所有元素并保存一个副本。当取完 iterable 中所有元素,返回副本中的所有元素。无限重复。大致相当于:

def cycle(iterable):

saved = []

for element in iterable:

yield element

saved.append(element) # 保存副本

while saved: # 副本不为空则无限循环

for element in saved: # 迭代副本

yield element

注意,该函数可能需要相当大的辅助空间(取决于 iterable 的长度)。

itertools.repeat(object[, times]):创建一个迭代器,不断重复 object 。除非设定参数 times ,否则将无限重复。可用于 map() 函数中的参数,被调用函数可得到一个不变参数。也可用于 zip() 的参数以在元组记录中创建一个不变的部分。

大致相当于:

def repeat(object, times=None):

if times is None: # times 为None,无限循环

while True:

yield object

else: # times 不为None,循环times次

for i in range(times):

yield object

根据最短输入序列长度停止的迭代器

itertools.accumulate(iterable[, func]):使迭代器返回累加的总和或其他形参为2各的函数的累加结果(通过可选的func参数指定)。如果提供了func,则它应该是两个参数的函数。输入iterable的元素可以是可以作为func的参数接受的任何类型。(例如,使用默认的加法运算,元素可以是任何可加类型,包括小数或分数。)如果输入iterable为空,则输出iterable也将为空。

大致相当于:

def accumulate(iterable, func=operator.add):

it = iter(iterable)

try:

total = next(it)

except StopIteration: # iterable为None,返回None

return

yield total

for element in it:

total = func(total, element) # 计算值

yield total

func 参数有几种用法。它可以被设为 min() 最终得到一个最小值,或者设为 max() 最终得到一个最大值,或设为 operator.mul() 最终得到一个乘积。

lis = [1,2,4,6,5]

print(list(itertools.accumulate(lis,max))) # [1, 2, 4, 6, 6]

itertools.chain(*iterables):创建一个迭代器,它首先返回第一个可迭代对象中所有元素,接着返回下一个可迭代对象中所有元素,直到耗尽所有可迭代对象中的元素。可将多个序列处理为单个序列。大致相当于:

def chain(*iterables):

for it in iterables:

for element in it:

yield element

lis1 = [1,6,5]

lis2 = [2,4,1]

print(list(itertools.chain(lis1,lis2))) # [1, 6, 5, 2, 4, 1]

classmethod chain.from_iterable(iterable):构建类似 chain() 迭代器的另一个选择。从一个单独的可迭代参数中得到链式输入,该参数是延迟计算的。大致相当于:

def from_iterable(iterables):

for it in iterables:

for element in it:

yield element

print(list(itertools.chain.from_iterable(['hello','world']))) # ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd']

itertools.compress(data, selectors):创建一个迭代器,它返回 data 中经 selectors 真值测试为 True 的元素。迭代器在两者较短的长度处停止。大致相当于:

def compress(data, selectors):

return (d for d, s in zip(data, selectors) if s)

print(list(itertools.compress('hello',[1,0,2,0,1]))) # ['h', 'l', 'o']

itertools.dropwhile(predicate, iterable):创建一个迭代器,如果 predicate 为true,迭代器丢弃这些元素,然后返回其他元素。注意,迭代器在 predicate 首次为false之前不会产生任何输出,所以可能需要一定长度的启动时间。大致相当于:

def dropwhile(predicate, iterable):

iterable = iter(iterable)

for x in iterable:

if not predicate(x): # predicate(x) 为True,不输出,直到遇到False,输出余下所有元素(包括判断为False的元素)

yield x

break

for x in iterable: # 迭代剩下的元素

yield x

print(list(itertools.dropwhile(lambda x : x < 3,[1,2,3,2,1]))) # [3, 2, 1]

itertools.filterfalse(predicate, iterable):创建一个迭代器,只返回 iterable 中 predicate 为 False 的元素。如果 predicate 是 None,返回真值测试为false的元素。大致相当于:

def filterfalse(predicate, iterable):

if predicate is None:

predicate = bool

for x in iterable:

if not predicate(x):

yield x

print(list(itertools.filterfalse(lambda x:x>5,range(10)))) # [0, 1, 2, 3, 4, 5]

itertools.groupby(iterable, key=None):创建一个迭代器,返回 iterable 中连续的键和组。key 是一个计算元素键值函数。如果未指定或为 None,key 缺省为恒等函数(identity function),返回元素不变。一般来说,iterable 需用同一个键值函数预先排序。

groupby() 操作类似于Unix中的 uniq。当每次 key 函数产生的键值改变时,迭代器会分组或生成一个新组(这就是为什么通常需要使用同一个键值函数先对数据进行排序)。这种行为与SQL的GROUP BY操作不同,SQL的操作会忽略输入的顺序将相同键值的元素分在同组中。

返回的组本身也是一个迭代器,它与 groupby() 共享底层的可迭代对象。因为源是共享的,当 groupby() 对象向后迭代时,前一个组将消失。因此如果稍后还需要返回结果,可保存为列表:

class groupby:

def __init__(self, iterable, key=None):

if key is None: # key = None,key 为恒等函数

key = lambda x: x

self.keyfunc = key

self.it = iter(iterable)

self.tgtkey = self.currkey = self.currvalue = object()

def __iter__(self):

return self

def __next__(self):

self.id = object()

while self.currkey == self.tgtkey: #第一次跳出循环是因为iterable不为空,currkey None,tgtkey为None

self.currvalue = next(self.it)

self.currkey = self.keyfunc(self.currvalue)

self.tgtkey = self.currkey # 以后每次跳出循环,tarkey赋新值,即可渠道连续两部的tgtkey,但只返回一次

return (self.currkey, self._grouper(self.tgtkey))

def _grouper(self, tgtkey):

'''找到与当前tgtkey相同的连续的currkey,输出currvalue迭代器'''

while self.currkey == tgtkey:

yield self.currvalue

try:

self.currvalue = next(self.it)

except StopIteration:

return

self.currkey = self.keyfunc(self.currvalue)

a = [list(g) for k, g in itertools.groupby('AAAABBBCCD')]

print(a) # [['A', 'A', 'A', 'A'], ['B', 'B', 'B'], ['C', 'C'], ['D']]

itertools.islice(iterable, stop)

itertools.islice(iterable, start, stop[, step]):

创建一个迭代器,返回从 iterable 里选中的元素。如果 start 不是0,跳过 iterable 中的元素,直到到达 start 这个位置。之后迭代器连续返回元素,除非 step 设置的值很高导致被跳过。如果 stop 为 None,迭代器耗光为止;否则,在指定的位置停止。与普通的切片不同,islice() 不支持将 start , stop ,或 step 设为负值。可用来从内部数据结构被压平的数据中提取相关字段(例如一个多行报告,它的名称字段出现在每三行上)。大致相当于:

def islice(iterable, *args):

s = slice(*args)

start, stop, step = s.start or 0, s.stop or sys.maxsize, s.step or 1

it = iter(range(start, stop, step))

try:

nexti = next(it)

except StopIteration:

for i, element in zip(range(start), iterable):

pass

return

try:

for i, element in enumerate(iterable):

if i == nexti:

yield element

nexti = next(it)

except StopIteration:

for i, element in zip(range(i + 1, stop), iterable):

pass

print(list(itertools.islice('ABCDEFG', 2))) # ['A', 'B']

print(list(itertools.islice('ABCDEFG', 2, 4))) # ['C', 'D']

print(list(itertools.islice('ABCDEFG', 2, None))) # ['C', 'D', 'E', 'F', 'G']

print(list(itertools.islice('ABCDEFG', 0, None, 2))) # ['A', 'C', 'E', 'G']

itertools.starmap(function, iterable):创建一个迭代器,使用从可迭代对象中获取的参数来计算该函数。当参数对应的形参已从一个单独可迭代对象组合为元组时(数据已被“预组对”)可用此函数代替 map()。map() 与 starmap() 之间的区别可以类比 function(a,b) 与 function(*c) 的区别。大致相当于:

def starmap(function, iterable):

for args in iterable:

yield function(*args)

print(list(itertools.starmap(pow, [(2,5), (3,2), (10,3)]) )) # [32, 9, 1000]

itertools.takewhile(predicate, iterable):创建一个迭代器,只要 predicate 为真就从可迭代对象中返回元素。大致相当于:

def takewhile(predicate, iterable):

for x in iterable:

if predicate(x):

yield x

else:

break

print(list(itertools.takewhile(lambda x: x<5, [1,4,6,4,1]))) # [1, 4]

itertools.tee(iterable, n=2):从一个可迭代对象中返回 n 个独立的迭代器。

下面的Python代码能帮助解释 tee 做了什么(尽管实际的实现更复杂,而且仅使用了一个底层的 FIFO 队列)。

大致相当于:

def tee(iterable, n=2):

it = iter(iterable)

deques = [collections.deque() for i in range(n)]

def gen(mydeque):

while True:

if not mydeque:

try:

newval = next(it)

except StopIteration:

return

for d in deques:

d.append(newval)

yield mydeque.popleft()

return tuple(gen(d) for d in deques)

iters = itertools.tee('hello',2)

for i in iters:

for data in i:

print(data)

itertools.zip_longest(*iterables, fillvalue=None):创建一个迭代器,从每个可迭代对象中收集元素。如果可迭代对象的长度未对齐,将根据 fillvalue 填充缺失值。迭代持续到耗光最长的可迭代对象。大致相当于:

def zip_longest(*args, fillvalue=None):

iterators = [iter(it) for it in args]

num_active = len(iterators)

if not num_active:

return

while True:

values = []

for i, it in enumerate(iterators):

try:

value = next(it)

except StopIteration:

num_active -= 1

if not num_active:

return

iterators[i] = repeat(fillvalue)

value = fillvalue

values.append(value)

yield tuple(values)

print(list(itertools.zip_longest('ABCD', 'xy', fillvalue='-')))

# [('A', 'x'), ('B', 'y'), ('C', '-'), ('D', '-')]

来源网络,侵权联系删除

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/4729/viewspace-3150640/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2019-07-17

  • 博文量
    294
  • 访问量
    13389