pipe:向 map 和 filter 说拜拜!

555 阅读2分钟

这是我参与 11 月更文挑战的第 4 天,活动详情查看:2021最后一次更文挑战

a = [1, 2, 3, 4, 5, 6] 中获得所有偶数的立方,你会怎么做?

你或许会回答我:

list(map(lambda x: x ** 3, filter(lambda x: x % 2 == 0, a)))

但有了 pipe 这个第三方库,代码变得简洁许多:

from pipe import select, where

list(a | select(lambda x: x ** 3) | where(lambda x: x % 2 == 0))

介绍

类似于 bash,pipe 库是中缀语法(infix syntax)在 Python 中的实现。这是一种很有新意的使用迭代器和生成器的方法 —— 把数据看作是流(stream)并在并在一系列函数中处理、传递。这种写法能大大地避免函数之间的嵌套,代码简洁有力!

老实说,看到这里,我已经想把我所有的代码重构了……(但当然不行)

pip 下载:

pip install pipe

那些使用的函数

select —— 内建 map 的替代

示例:求前 100 个自然数的平方和与总和的平方之间的差。(Project Euler 第六题)

sum(range(101)) ** 2 - sum(range(101) | select(lambda x: x ** 2))

where —— 内建 filter 的替代

示例:计算 1000 以下所有 3 或 5 的倍数之和。(Project Euler 第一题)

sum(range(1000) | where(lambda x: x % 3 == 0 or x % 5 == 0))

take_whileskip_while —— itertools.takewhileitertools.dropwhile 的替代

take_while 当 lambda 表达式为真时就返回元素,skip_while 则相反。

示例:考虑斐波那契数列中值不大于 4000000 的项,找出偶数值项的总和。(Project Euler 第二题)

def fib(a, b):
  ...

sum(fib(1, 2) | where(lambda x: x % 2 == 0) | take_while(lambda x: x < 4000000))

chain —— 链接几组可迭代对象

示例:

>>> list([[1, 2], [3, 4], [5]] | chain)
[1, 2, 3, 4, 5]

chain 只展开只包含可迭代的可迭代:,像是 [1, 2, [3]] 这种是不行的,抛出 TypeError

traverse —— 递归展开可迭代对象

对于扁平化可迭代非常有用。

示例:

>>> list([1, 2, [3]] | traverse)
[1, 2, 3]
>>> list([[1, 2], [[[3], [[4]]], [5]]] | traverse)
[1, 2, 3, 4, 5]

dedupuniq —— 去重函数

示例:

>>> list([1, 1, 2, 2, 3, 3, 1, 2, 3] | dedup)
[1, 2, 3]
>>> list([1, 1, 2, 2, 3, 3, 1, 2, 3] | dedup(key=lambda n: n % 2))
[1, 2]

uniqdedup 类似,但只对连续值进行重复数据删除。

>>> list([1, 1, 2, 2, 3, 3, 1, 2, 3] | uniq)
[1, 2, 3, 1, 2, 3]
>>> list([1, 1, 2, 2, 3, 3, 1, 2, 3] | uniq(key=lambda n: n % 2))
[1, 2, 3, 2, 3]

这里只举例几个比较常用的函数,欲知更多请参阅文档

下一篇文章带大家扒一扒这个库的源码,拜拜~