Python中的新运算符 [英] New operators in Python
问题描述
我们可以在此处中定义Python的内在运算符.出于好奇,我们是否可以定义新的运算符,例如$
或***
? (如果是这样,那么我们可以定义三元条件运算符或旋转运算符.)
We can define intrinsic operators of Python as stated here. Just for curiosity, can we define new operators like $
or ***
? (If so, then we can define ternary condition operators or rotate operators.)
推荐答案
扩展@fasouto答案,但添加更多代码.
Expanding on @fasouto answer, but adding a bit more code.
虽然不能定义新的运算符,也不能为内置类型重新定义现有的运算符,但是您可以做的是定义一个类(实例化为任何有效的Python名称,例如op
),该类充当以下操作的中间绑定:两个对象,因此实际上看起来像一个二进制中缀运算符:
While you cannot define new operators AND you cannot redefine existing operators for built-in types, what you can do is to define a class (instantiated to any valid Python name, e.g. op
) that act as an intermediate binding for two objects, thus effectively looking like a binary infix operator:
a | op | b
非约束性实现
简而言之,可以为操作员定义一个覆盖 forward 和 backward 方法的类,例如__or__
和__ror__
用于|
运算符:
Non-binding Implementation
In short, one can define a class overriding forward and backward methods for an operator, e.g. __or__
and __ror__
for the |
operator:
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
表达式不能单独使用 :
The above solution works as is, but there are some issues, e.g. op | 2
expression cannot be used alone:
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
绑定实现
要获得适当的绑定,可能需要编写一些更复杂的代码来执行中间的 binding :
Binding Implementation
To get proper bindings one would need to write a bit more complex code performing an intermediate binding:
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)
此方法的使用方式与以前相同,例如要么:
This is used the same way as before, e.g. either:
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/
There is also a PyPI package implementing substantially this: https://pypi.org/project/infix/
顺便说一句,绑定解决方案似乎也快一些:
Incidentally, the binding solutions seems to be also marginally faster:
%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
注释
这些实现使用|
,但是可以使用任何二进制运算符:
Notes
These implementations use |
, but any binary operator could be used:
-
+
:__add__
-
-
:__sub__
-
*
:__mul__
-
/
:__truediv__
-
//
:__floordiv__
-
%
:__mod__
-
**
:__pow__
-
@
:__matmul__
(适用于Python 3.5及更高版本) -
|
:__or__
-
&
:__and__
-
^
:__xor__
-
>>
:__rshift__
-
<<
:__lshift__
+
:__add__
-
:__sub__
*
:__mul__
/
:__truediv__
//
:__floordiv__
%
:__mod__
**
:__pow__
@
:__matmul__
(for Python 3.5 onwards)|
:__or__
&
:__and__
^
:__xor__
>>
:__rshift__
<<
:__lshift__
**
将需要绑定实现或调整非绑定实现,以反映操作员是 right-associative .上面的所有其他运算符都是左关联(-
,/
,//
,%
,@
,>>
,<<
)或直接可交换的(+
,*
,|
,&
,^
).
The **
would require the binding implementation or adjusting the non-binding one to reflect that the operator is right-associative. All the other operators from above are either left-associative (-
, /
, //
, %
, @
, >>
, <<
) or directly commutative (+
, *
, |
, &
, ^
).
请记住,它们的优先级都与普通的Python运算符相同,例如:
Remember that these would all have the same precedence as the normal Python operators, hence, e.g.:
(1 | op | 2 * 5) == (1 | op | (2 * 5)) != ((1 | op | 2) * 5)
这篇关于Python中的新运算符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!