探秘Python的Pipeline魔法

VOL.137329 views

1

Mar. 2024

如果你是一个Python开发者,你可能听过"pipeline"这个术语。但 pipeline 到底是什么,它又有什么用呢?在这篇文章中,我们将探讨 Python 中的 pipeline 概念,它们是如何工作的,以及它们如何帮助你编写更清晰、更高效的代码。

什么是 Pipeline?

Pipeline 是一种组织一系列操作或函数来处理数据的方式。一个操作的输出成为下一个操作的输入,依此类推,直到得到最终结果。Pipeline 可以被视为一系列管道,数据从一个管道流向另一个管道,在此过程中进行一些转换或操作。

举个例子,假设你有一个数字列表,你想对它们执行以下操作:

  • 过滤出奇数
  • 将每个数字乘以10
  • 每个数字加5
  • 计算结果数字的平均值

一种方法是编写一个循环,迭代列表并逐个应用每个操作,将中间结果存储在一个新列表中。例如:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
filtered = []
for n in numbers:
    if n % 2 == 0:
        filtered.append(n)
multiplied = []
for n in filtered:
    multiplied.append(n * 10)
added = []
for n in multiplied:
    added.append(n + 5)
total = 0
count = 0
for n in added:
    total += n
    count += 1
average = total / count
print(average)

这段代码可以工作,但不够优雅和高效。它创建了三个新列表,占用内存,使代码难以阅读。它还需要编写四个循环,这可能会很繁琐且容易出错。

更好的方法是使用 pipeline。Pipeline 允许你将操作链接在一起,而无需创建中间列表或循环。你可以使用内置的 map 和 filter 函数,它们接受一个函数和一个可迭代对象作为参数,并返回一个将函数应用于原始可迭代对象的每个元素的新可迭代对象。你还可以使用 sum 和 len 函数,分别计算可迭代对象的总和和长度。例如:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
average = sum(map(lambda n: n + 5, map(lambda n: n * 10, filter(lambda n: n % 2 == 0, numbers)))) / len(numbers)
print(average)

这段代码比之前的代码要短和简单得多。它不创建任何新列表或循环,并且很容易看出数据从一个操作流向下一个操作。然而,它仍然不够可读,因为它使用了嵌套的 map 和 filter 调用,这可能会令人困惑且难以理解。

一个更易读的的方法是使用 toolz 库中的 pipe 函数编写 pipeline 。pipe函数接受一个初始值和一系列函数,并将每个函数应用于前一个函数的输出,返回最终结果。例如:

from toolz import pipe
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
average = pipe(numbers, 
               filter(lambda n: n % 2 == 0), 
               map(lambda n: n * 10), 
               map(lambda n: n + 5), 
               lambda x: sum(x) / len(x))
print(average)

这段代码比之前的代码更可读和优雅。它清楚地展示了应用于数据的操作序列,而且没有使用任何嵌套调用或中间列表。pipe 函数使代码看起来像一个流水线,数据从一个函数流向下一个函数。

为什么使用 Pipeline?

Pipeline 相对于其他代码组织方式有几个优点,其中一个是:

  • 可读性:Pipeline 使代码更易读和理解,因为它展示了数据从一个操作流向下一个操作的流程,而不会在代码中引入中间变量或循环。Pipeline 还使代码更模块化和可重用,因为每个操作可以定义为一个独立的函数,可以轻松测试并在不同的上下文中重用。

  • 效率:Pipeline 可以提高代码的效率,因为它避免了创建占用内存并减慢执行速度的中间列表或可迭代对象。Pipeline 还允许惰性求值,这意味着只有在需要数据时才执行操作,而不是提前执行。这可以节省时间和资源,特别是在处理大量或无限数据源时。

+灵活性:Pipeline 可以轻松修改或扩展,因为它允许添加、删除或更改操作的顺序,而不影响其他部分的代码。Pipeline 还支持不同类型的操作,例如过滤、映射、归约、聚合、分组、排序等,可以以各种方式组合以达到不同的结果。

如何在Python中使用Pipeline?

在 Python 中,有多种创建和使用 Pipeline 的方法,其中一些包括:

  1. 使用内置函数:Python 提供了几个内置函数,可以用于创建Pipeline,例如 map、filter、reduce、zip、enumerate、sorted、reversed 等。这些函数接受一个函数和一个可迭代对象作为参数,并返回一个将函数应用于原始可迭代对象的每个元素的新可迭代对象。

  2. 使用列表推导式:列表推导式是一种简洁和表达力强的方式,在 Python中 创建列表,它使用类似数学表示的语法。列表推导式也可以用于创建 Pipeline,通过将一系列操作应用于可迭代对象的每个元素,并将结果收集到一个新列表中。

  3. 使用生成器表达式:生成器表达式类似于列表推导式,但它们返回一个生成器对象,而不是列表。生成器对象是一个按需产生元素的可迭代对象,而不是在内存中存储它们。生成器表达式也可以用于创建 Pipeline,通过将一系列操作应用于可迭代对象的每个元素,并将结果作为生成器产生。

总结

希望这篇文章能够帮助你理解什么是Pipeline以及如何在Python中使用它们。如果你有任何问题或反馈,请在下方评论留言。