Python中的新运算符
问题内容:
为表示我们可以定义的Python的内在运营商这里。出于好奇,我们可以定义新的运算符,例如$
还是***
?(如果是这样,那么我们可以定义三元条件运算符或旋转运算符。)
问题答案:
扩展@fasouto答案,但添加更多代码。
虽然您不能定义新的运算符,也不能为内置类型重新定义现有的运算符,但是您可以做的是定义一个类(实例化为任何有效的Python名称op
),该类充当两个对象的中间绑定,从而有效地查找像二进制中缀运算符一样:
a | op | b
非约束性实施
总之,可以定义一个类中重写 向前 和 向后 操作员,例如使用的方法__or__
和__ror__
用于|
操作者:
class Infix:
def __init__(self, function):
self.function = function
def __ror__(self, other):
return Infix(lambda x, self=self, other=other: self.function(other, x))
def __or__(self, other):
return self.function(other)
def __call__(self, value1, value2):
return self.function(value1, value2)
可以直接使用:
op = Infix(lambda a, b: a + b) # can be any bivariate function
1 | op | 2
# 3
或作为装饰者:
@Infix
def op(a, b):
return a + b
1 | op | 2
# 3
上述解决方案工作方式是,但也存在一些问题,如op | 2
表达不能用 单纯 :
op = Infix(lambda a, b: a + b)
(1 | op)
#<__main__.Infix object at 0x7facf8f33d30>
# op | 2
# TypeError: <lambda>() missing 1 required positional argument: 'b'
1 | op | 2)
# 3
绑定实现
为了获得适当的绑定,需要编写一些更复杂的代码来执行中间 绑定 :
class Infix(object):
def __init__(self, func):
self.func = func
class RBind:
def __init__(self, func, binded):
self.func = func
self.binded = binded
def __call__(self, other):
return self.func(other, self.binded)
__ror__ = __call__
class LBind:
def __init__(self, func, binded):
self.func = func
self.binded = binded
def __call__(self, other):
return self.func(self.binded, other)
__or__ = __call__
def __or__(self, other):
return self.RBind(self.func, other)
def __ror__(self, other):
return self.LBind(self.func, other)
def __call__(self, value1, value2):
return self.func(value1, value2)
使用方法与以前相同,例如:
op = Infix(lambda a, b: a + b)
或作为装饰者:
@Infix
def op(a, b):
return a + b
有了这个,就会得到:
1 | op
# <__main__.Infix.LBind object at 0x7facf8f2b828>
op | 2
# <__main__.Infix.RBind object at 0x7facf8f2be10>
1 | op | 2
# 3
还有一个PyPI软件包,基本上实现了此功能:https :
//pypi.org/project/infix/
时机
顺便说一句,绑定解决方案似乎也快一些:
%timeit [1 | op | 2 for _ in range(1000)]
# Non-binding implementation
# 1000 loops, best of 3: 626 µs per loop
# Binding implementation
# 1000 loops, best of 3: 525 µs per loop
笔记
这些实现使用|
,但是可以使用任何二进制运算符:
+
:__add__
-
:__sub__
*
:__mul__
/
:__truediv__
//
:__floordiv__
%
:__mod__
**
:__pow__
@
:(__matmul__
适用于Python 3.5及更高版本)|
:__or__
&
:__and__
^
:__xor__
>>
:__rshift__
<<
:__lshift__
这**
需要绑定实现或调整非绑定实现以反映操作符是 右关联的 。从上面的所有其他运营商要么 左结合
(-
,/
,//
,%
,@
,>>
,<<
),或直接交换(+
,*
,|
,&
,^
)。
请记住,它们都将具有与普通Python运算符相同的优先级,因此,例如:
(1 | op | 2 * 5) == (1 | op | (2 * 5)) != ((1 | op | 2) * 5)