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.)
As @minitech said you can't define new operators. But check this hack that allows you to define infix operators http://code.activestate.com/recipes/384122-infix-operators/
Expanding on @fasouto answer, but adding a bit more code.
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
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)
This can be used directly:
op = Infix(lambda a, b: a + b)  # can be any bivariate function
1 | op | 2
# 3
or as a decorator:
@Infix
def op(a, b):
    return a + b
1 | op | 2
# 3
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
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)
or as a decorator:
@Infix
def op(a, b):
    return a + b
With this, one would get:
1 | op
# <__main__.Infix.LBind object at 0x7facf8f2b828>
op | 2
# <__main__.Infix.RBind object at 0x7facf8f2be10>
1 | op | 2
# 3
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
These implementations use |, but any binary operator could be used:
+: __add__
-: __sub__
*: __mul__
/: __truediv__
//: __floordiv__
%: __mod__
**: __pow__
@: __matmul__ (for Python 3.5 onwards)|: __or__
&: __and__
^: __xor__
>>: __rshift__
<<: __lshift__
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 (+, *, |, &, ^).
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)
                        No, you can’t define new operators in Python.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With