Python中重载操作符实现管道操作
在LangChain创建一个chain的新方式是使用LCEL的表达式,例如
chain = prompt | model | output_parser
这样的代码又清晰又性感,特别是对于熟悉Linux管道(pipes)操作的同学来说太亲切了。那么如何在我们自己的Python代码中实现这种链式的管道操作呢?实际上,实现这样的功能并不复杂,让我们一起看看吧。
熟悉Python的同学们估计也猜到了,如同这一类魔法操作,常常是为自定义类型实现一些内建的特殊函数,例如__str__, __getitem__, __dict__等等操作。今天的主角是两个函数,__or__和__ror__。
在Python中,当解释器看到表达式
a | b
的时候,它会:
(1) 如果a对象的类实现了__or__则调用a.__or__, 传入的参数是b对象;
(2) 如果a没有实现__or__操作,而b实现了__ror__则调用b.__ror__, 传入的参数是a对象;
(3) 如果a和b都很乖,分别实现了两种操作符重载,那么按照优先级次序调用a.__or__,而b的方法会被忽略;
(4) 最后就是都不满足的情况那就不用说了,同学们自己试试。
是不是很简单啊?接下来show time看几个简单例子加深印象。首先是一个看起来没什么用仔细看也的确没什么用的echo。
class Echo:def __ror__(self, value):return valueecho = Echo()
s = "hello" | echo
print("hello" | echo)
print( 1 + 1 | echo)
下面的例子是实现increase和square功能,
class Increase:def __init__(self, value=None):self.value = value if value != None else 0def __or__(self, delta):print("Increase.__or__ is called")self.value += deltareturn self.valuedef __ror__(self, other):print("Increase.__xor__ is called")if type(other) == int or type(other) == float:self.value = other + 1else:self.value = other.value + 1return self.valuedef __str__(self):return f'{self.value}'class Square:def __init__(self):self.value = 0def __or__(self, other):print("Square.__or__ is called")self.value = other * otherreturn self.valuedef __ror__(self, other):print("Square.__xor__ is called")self.value = other * otherreturn self.valuedef __str__(self):return f'{self.value}'
注意这里两个类都实现了__or__和__xor__, 是为了demo的目的,同学们根据实际情况决定实现哪个方法就可以了。例如下面的用法中,其实只会用到__ror__操作。
if __name__ == '__main__':increase = Increase()i = 1 | increase | increaseprint(i)square = Square()x = 9 | squareprint(x)print( 5 | square | increase | echo)
这样的写法更加符合大家使用管道的习惯,也就是数据从左向右边流动。
而下面的用法,我觉得有点别扭。
increase = Increase(9)
print(increase | 1)square = Square()
print(square | 9)
好了,不bb了,各位国庆快乐,happy coding.