首页 > 应用开发 > > Python 标准库 itertools
狮范课
为高效循环而创建迭代器的函数
无穷迭代器
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/ ,如需转载,请注明出处,否则将追究法律责任。