Python:如何定义自己的运算符?

106

我想定义自己的运算符。Python支持这样的操作吗?


1
好的,你可以定义一个未定义的运算符(比如$),然后使用一些Python代码来编辑自己(使用open函数),将所有的 a $ b 替换为 function(a,b) - whackamadoodle3000
6个回答

216

虽然在Python中技术上无法定义新的运算符,但是这个巧妙的技巧可以绕过此限制。它允许你像这样定义中缀运算符:

# simple multiplication
x=Infix(lambda x,y: x*y)
print 2 |x| 4
# => 8

# class checking
isa=Infix(lambda x,y: x.__class__==y.__class__)
print [1,2,3] |isa| []
print [1,2,3] <<isa>> []
# => True

2
+1 这个黑科技很酷,但我不认为它在这种情况下会起作用。 - Zifre
15
这可能是一个有趣的技巧,但我认为这不是一个好的解决方案。Python不允许创建自己的运算符,这是出于良好原因的设计决策,你应该接受它,而不是把它看作一个问题并想出绕过它的方法。与你编写代码的语言对抗并不是一个好主意。如果你真的想要这样做,应该使用另一种语言。 - DasIch
110
@DasIch 我非常不同意。我们并不都可以自由选择一种语言。另一方面,如果我不满意,我不明白为什么我要接受其他人的设计决策。- 确实是一个很棒的技巧! - ThomasH
2
我刚刚将它与toolzpipe结合了起来。 pip = Infix(lambda x,y: pipe(x,y)),然后8 |pip| range |pip| sum |pip| range。看起来可以正常工作。 - cantdutchthis
1
有趣的解决方案,但也许仍然比实际定义运算符(在Python中无法进行预处理)稍逊一筹的是,在参数被评估之前,您无法访问它们。因此,您不能定义自己的赋值运算符或控制评估顺序,例如and运算符。 - Yushin Washio
显示剩余2条评论

49

不,Python 附带有一个预定义的、可被覆盖的一组操作符


1
我很好奇dfply如何使用-->运算符:https://towardsdatascience.com/dplyr-style-data-manipulation-with-pipes-in-python-380dcb137000 - Max Candocia
2
据我所知,它似乎不支持(请参阅文档)。那篇文章中使用“-->”的示例似乎是伪代码。该库本身只是重载了“>>”。 - Andrew Marshall

42

不可以创建新的运算符。但是,如果您只是要评估表达式,您可以处理字符串并计算新运算符的结果。


1
请参见以下链接以查看Python中可重载的一组预定义运算符:下方链接 - Palimondo

14

Sage提供了这个功能,基本上使用了@Ayman Hourieh描述的“聪明的技巧”,但是将其作为装饰器并结合到模块中,以使外观更清晰,并提供额外的功能 - 您可以选择要重载的运算符,因此也可以选择评估顺序。

from sage.misc.decorators import infix_operator

@infix_operator('multiply')
def dot(a,b):
    return a.dot_product(b)
u=vector([1,2,3])
v=vector([5,4,3])
print(u *dot* v)
# => 22

@infix_operator('or')
def plus(x,y):
    return x*y
print(2 |plus| 4)
# => 6

请查看Sage文档此增强跟踪工单以获取更多信息。


14

Python 3.5引入了符号@以作为额外的运算符。

PEP465引入了这个新运算符,用于简化许多数值代码的表示。该运算符不会为所有类型实现,而仅针对数组状对象。

您可以通过实现__matmul__()来支持该运算符用于您的类/对象。

该PEP留出了空间,使非数组状对象可以使用不同的运算符用途。

当然,您也可以用@实现任何与矩阵乘法不同的操作,但用户体验将受到影响,因为每个人都期望您的数据类型表现出不同的行为。


1
你的意思是 @ 是一个新的操作符号吗?还是说我们可以用它来定义自己的新操作符? - Addem
是的,@ 是一个新的操作符号。您可以使用它来定义对象上的操作。请考虑阅读PEP465。 - gg349
9
他的意思是@是一个新的操作符。这就是它的全部含义。事实仍然存在:你不能在Python中定义自己的操作符。 - John Red

12

如果您想将操作应用于特定类的对象,可以覆盖与功能最接近的运算符...例如,覆盖 __eq__() 将覆盖 == 运算符并返回您想要的结果。这适用于几乎所有的运算符。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接