一. 概述
我们都知道在Linux下执行命令ls | sort -r
会将排序后的结果进行输出,它是先获取目录数据,管道符|
将ls的输出作为后一个命令的输入,最终得到反向排序的结果。
Python和其他大多数语言一样,处理数据的时候通常是将数据作为参数传入。但是有没有像Linux管道符那样优雅的输出呢?有的,这就是pipe
模块,但需要注意的是pipe
模块并不属于Python的标准库,可用pip pipe
进行安装。
二. 使用
pipe
的使用方法很简单,只需要给处理数据的函数加上@Pipe
注解就OK了。如下,
from pipe import *
@Pipe
def Filter(lst):
return [x for x in lst if x > 3]
def GetNums():
return [1, 2, 3, 4, 5]
res = GetNums() | Filter()
print(res)
输出:
[4, 5]
三. 原理
pipe
的实现原理和它的使用方式一样简单(正因为简单,才有这篇笔记(╥﹏╥)
)。它的核心代码只有几行,实际就是一个装饰器。
class Pipe:
def __init__(self, function):
self.function = function
functools.update_wrapper(self, function)
def __ror__(self, other):
return self.function(other)
def __call__(self, *args, **kwargs):
return Pipe(lambda x: self.function(x, *args, **kwargs))
好,既然这么简单。我们第二章中的例子自己实现一次,并添加了一些注释和辅助分析的输出。
# 装饰器
class Pipe:
def __init__(self, function):
print(f"__init__调用,实例id为:{id(self)}")
self.function = function
# # 保留传入函数的元信息,可忽略
# functools.update_wrapper(self, function)
def __ror__(self, other):
print(f"__ror__被调用,传入的参数是:{other}")
return self.function(other)
def __call__(self, *args, **kwargs):
print("__call__被调用")
# 返回的是一个Pipe对象,这样就能够使用重载的“|”
# 传入一个lambda表达式,是对self.function的再一次封装,回报存在这个Pipe对象的self.function中
return Pipe(lambda x: self.function(x, *args, **kwargs))
@Pipe
def Filter(lst):
print("Filter被调用")
return [x for x in lst if x > 3]
print("----- 分割线 -----")
def GetNums():
return [1, 2, 3, 4, 5]
res = GetNums() | Filter()
print(res)
输出:
__init__调用,实例id为:2398974542568
----- 分割线 -----
__call__被调用
__init__调用,实例id为:2398974542624
__ror__被调用,传入的参数是:[1, 2, 3, 4, 5]
Filter被调用
[4, 5]
从结果可以看到,Filter()
的作用过程是这样的:
Pipe
装饰器包装函数Filter
;Filter()
的调用实际上就是调用Pipe
实例中的__call__
方法;- 在
__call__
方法中,用lambda对实际的Filter
函数再做一次封装(其实这个lambda可以省去的,可自行验证),并传入该lambda表达式生成一个新的Pipe
对象; - 之后是将
GetNums()
函数的返回值作为操作数,传入到__ror__
中; - 在
__ror__
方法中,调用self.function
(实际的Filter
函数)处理处理数据,返回结果。