[Python] pipe模块

一. 概述

我们都知道在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()的作用过程是这样的:

  1. Pipe装饰器包装函数Filter
  2. Filter()的调用实际上就是调用Pipe对象中的__call__方法;
  3. __call__方法中,用lambda对实际的Filter函数再做一次封装(其实这个lambda可以省去的,可自行验证),并传入该lambda表达式生成一个新的Pipe对象;
  4. 之后是将GetNums()函数的返回值作为操作数,传入到__ror__中;
  5. __ror__方法中,调用self.function(实际的Filter函数)处理处理数据,返回结果。
posted @ 2024-05-23 16:30  小贼的自由  阅读(201)  评论(0编辑  收藏  举报