资讯专栏INFORMATION COLUMN

PyTips 0x16 - Python 迭代器工具

mayaohua / 2749人阅读

摘要:借鉴了中的某些迭代器的构造方法,并在中实现该模块是通过实现,源代码。

项目地址:https://git.io/pytips

0x01 介绍了迭代器的概念,即定义了 __iter__()__next__() 方法的对象,或者通过 yield 简化定义的“可迭代对象”,而在一些函数式编程语言(见 0x02 Python 中的函数式编程)中,类似的迭代器常被用于产生特定格式的列表(或序列),这时的迭代器更像是一种数据结构而非函数(当然在一些函数式编程语言中,这两者并无本质差异)。Python 借鉴了 APL, Haskell, and SML 中的某些迭代器的构造方法,并在 itertools 中实现(该模块是通过 C 实现,源代码:/Modules/itertoolsmodule.c)。

itertools 模块提供了如下三类迭代器构建工具:

无限迭代

整合两序列迭代

组合生成器

1. 无限迭代

所谓无限(infinite)是指如果你通过 for...in... 的语法对其进行迭代,将陷入无限循环,包括:

count(start, [step])

cycle(p)

repeat(elem [,n])

从名字大概可以猜出它们的用法,既然说是无限迭代,我们自然不会想要将其所有元素依次迭代取出,而通常是结合 map/zip 等方法,将其作为一个取之不尽的数据仓库,与有限长度的可迭代对象进行组合操作:

from itertools import cycle, count, repeat
print(count.__doc__)
count(start=0, step=1) --> count object

Return a count object whose .__next__() method returns consecutive values.
Equivalent to:

    def count(firstval=0, step=1):
        x = firstval
        while 1:
            yield x
            x += step

counter = count()
print(next(counter))
print(next(counter))
print(list(map(lambda x, y: x+y, range(10), counter)))

odd_counter = map(lambda x: "Odd#{}".format(x), count(1, 2))
print(next(odd_counter))
print(next(odd_counter))
0
1
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Odd#1
Odd#3
print(cycle.__doc__)
cycle(iterable) --> cycle object

Return elements from the iterable until it is exhausted.
Then repeat the sequence indefinitely.
cyc = cycle(range(5))
print(list(zip(range(6), cyc)))
print(next(cyc))
print(next(cyc))
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 0)]
1
2
print(repeat.__doc__)
repeat(object [,times]) -> create an iterator which returns the object
for the specified number of times.  If not specified, returns the object
endlessly.
print(list(repeat("Py", 3)))
rep = repeat("p")
print(list(zip(rep, "y"*3)))
["Py", "Py", "Py"]
[("p", "y"), ("p", "y"), ("p", "y")]
2. 整合两序列迭代

所谓整合两序列,是指以两个有限序列为输入,将其整合操作之后返回为一个迭代器,最为常见的 zip 函数就属于这一类别,只不过 zip 是内置函数。这一类别完整的方法包括:

accumulate()

chain()/chain.from_iterable()

compress()

dropwhile()/filterfalse()/takewhile()

groupby()

islice()

starmap()

tee()

zip_longest()

这里就不对所有的方法一一举例说明了,如果想要知道某个方法的用法,基本通过 print(method.__doc__) 就可以了解,毕竟 itertools 模块只是提供了一种快捷方式,并没有隐含什么深奥的算法。这里只对下面几个我觉得比较有趣的方法进行举例说明。

from itertools import cycle, compress, islice, takewhile, count

# 这三个方法(如果使用恰当)可以限定无限迭代
# print(compress.__doc__)
print(list(compress(cycle("PY"), [1, 0, 1, 0])))

# 像操作列表 l[start:stop:step] 一样操作其它序列
# print(islice.__doc__)
print(list(islice(cycle("PY"), 0, 2)))

# 限制版的 filter
# print(takewhile.__doc__)
print(list(takewhile(lambda x: x < 5, count())))
["P", "P"]
["P", "Y"]
[0, 1, 2, 3, 4]
from itertools import groupby
from operator import itemgetter
print(groupby.__doc__)

for k, g in groupby("AABBC"):
    print(k, list(g))
db = [dict(name="python", script=True),
      dict(name="c", script=False),
      dict(name="c++", script=False),
      dict(name="ruby", script=True)]
keyfunc = itemgetter("script")

db2 = sorted(db, key=keyfunc) # sorted by `script"
for isScript, langs in groupby(db2, keyfunc):
    print(", ".join(map(itemgetter("name"), langs)))
groupby(iterable[, keyfunc]) -> create an iterator which returns
(key, sub-iterator) grouped by each value of key(value).

A ["A", "A"]
B ["B", "B"]
C ["C"]
c, c++
python, ruby
from itertools import zip_longest

# 内置函数 zip 以较短序列为基准进行合并,
# zip_longest 则以最长序列为基准,并提供补足参数 fillvalue
# Python 2.7 中名为 izip_longest

print(list(zip_longest("ABCD", "123", fillvalue=0)))
[("A", "1"), ("B", "2"), ("C", "3"), ("D", 0)]
3. 组合生成器

关于生成器的排列组合:

product(*iterables, repeat=1):两输入序列的笛卡尔乘积

permutations(iterable, r=None):对输入序列的完全排列组合

combinations(iterable, r):有序版的排列组合

combinations_with_replacement(iterable, r):有序版的笛卡尔乘积

from itertools import product, permutations, combinations, combinations_with_replacement
print(list(product(range(2), range(2))))
print(list(product("AB", repeat=2)))
[(0, 0), (0, 1), (1, 0), (1, 1)]
[("A", "A"), ("A", "B"), ("B", "A"), ("B", "B")]
print(list(combinations_with_replacement("AB", 2)))
[("A", "A"), ("A", "B"), ("B", "B")]
# 赛马问题:4匹马前2名的排列组合(A^4_2)
print(list(permutations("ABCDE", 2)))
[("A", "B"), ("A", "C"), ("A", "D"), ("A", "E"), ("B", "A"), ("B", "C"), ("B", "D"), ("B", "E"), ("C", "A"), ("C", "B"), ("C", "D"), ("C", "E"), ("D", "A"), ("D", "B"), ("D", "C"), ("D", "E"), ("E", "A"), ("E", "B"), ("E", "C"), ("E", "D")]
# 彩球问题:4种颜色的球任意抽出2个的颜色组合(C^4_2)
print(list(combinations("ABCD", 2)))
[("A", "B"), ("A", "C"), ("A", "D"), ("B", "C"), ("B", "D"), ("C", "D")]
总结

迭代器工具在产生数据的时候将会显得非常便捷、高效,掌握了这些基本的方法之后,通过简单的组合就可以获得更多迭代器工具。


欢迎关注公众号 PyHub 每日推送

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/45422.html

相关文章

  • PyTips 0x01 - 迭代与生成

    摘要:项目地址迭代器与生成器迭代器与生成器是中比较常用又很容易混淆的两个概念,今天就把它们梳理一遍,并举一些常用的例子。生成器前面说到创建迭代器有种方法,其中第三种就是生成器。 项目地址:https://git.io/pytips 迭代器与生成器 迭代器(iterator)与生成器(generator)是 Python 中比较常用又很容易混淆的两个概念,今天就把它们梳理一遍,并举一些常用的例...

    chemzqm 评论0 收藏0
  • PyTips 0x0d - Python 上下文管理

    摘要:项目地址引入了语句与上下文管理器类型,其主要作用包括保存重置各种全局状态,锁住或解锁资源,关闭打开的文件等。了解了语句的执行过程,我们可以编写自己的上下文管理器。生成器的写法更简洁,适合快速生成一个简单的上下文管理器。 项目地址:https://git.io/pytips Python 2.5 引入了 with 语句(PEP 343)与上下文管理器类型(Context Manager ...

    yuxue 评论0 收藏0
  • PyTips 0x13 - Python 线程与协程(2)

    摘要:项目地址我之前翻译了协程原理这篇文章之后尝试用了模式下的协程进行异步开发,确实感受到协程所带来的好处至少是语法上的。 项目地址:https://git.io/pytips 我之前翻译了Python 3.5 协程原理这篇文章之后尝试用了 Tornado + Motor 模式下的协程进行异步开发,确实感受到协程所带来的好处(至少是语法上的:D)。至于协程的 async/await 语法是如...

    史占广 评论0 收藏0
  • PyTips 0x0e - Python 内置排序方法

    摘要:项目地址提供两种内置排序方法,一个是只针对的原地排序方法,另一个是针对所有可迭代对象的非原地排序方法。 项目地址:https://git.io/pytips Python 提供两种内置排序方法,一个是只针对 List 的原地(in-place)排序方法 list.sort(),另一个是针对所有可迭代对象的非原地排序方法 sorted()。 所谓原地排序是指会立即改变被排序的列表对象,就...

    Baoyuan 评论0 收藏0
  • PyTips 0x03 - Python 列表推导

    摘要:项目地址列表推导中提到的方法可以通过简化的语法快速构建我们需要的列表或其它可迭代对象,与它们功能相似的,还提供列表推导的语法。 项目地址:https://git.io/pytips 0x03 - Python 列表推导 0x02 中提到的 map/filter 方法可以通过简化的语法快速构建我们需要的列表(或其它可迭代对象),与它们功能相似的,Python 还提供列表推导(List C...

    sugarmo 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<