Python中的新运算符

xxx*_*--- 4 python operators operator-keyword

为表示我们可以定义的Python的内在运营商这里.只是为了好奇,我们可以定义像$或的新运算符***吗?(如果是这样,那么我们可以定义三元条件运算符或旋转运算符.)

fas*_*uto 7

正如@minitech所说,你无法定义新的运营商.但是检查这个允许你定义中缀运算符的hack http://code.activestate.com/recipes/384122-infix-operators/


nor*_*ok2 5

扩展@fasouto 答案,但添加更多代码。

\n

虽然您不能定义新的运算符,也不能为内置类型重新定义现有的运算符,但您可以做的是定义一个类(实例化为任何有效的 Python 名称,例如op)作为两个对象的中间绑定,从而有效地查找就像二元中缀运算符:

\n
a | op | b\n
Run Code Online (Sandbox Code Playgroud)\n

非约束性实施

\n

简而言之,可以为运算符定义一个覆盖前向后向__or__方法的类,例如和__ror__运算|符:

\n
class Infix:\n    def __init__(self, function):\n        self.function = function\n    def __ror__(self, other):\n        return Infix(lambda x, self=self, other=other: self.function(other, x))\n    def __or__(self, other):\n        return self.function(other)\n    def __call__(self, value1, value2):\n        return self.function(value1, value2)\n
Run Code Online (Sandbox Code Playgroud)\n

这个可以直接使用:

\n
op = Infix(lambda a, b: a + b)  # can be any bivariate function\n\n1 | op | 2\n# 3\n
Run Code Online (Sandbox Code Playgroud)\n

或作为装饰器:

\n
@Infix\ndef op(a, b):\n    return a + b\n\n1 | op | 2\n# 3\n
Run Code Online (Sandbox Code Playgroud)\n

上面的解决方案按原样工作,但存在一些问题,例如表达式不能单独op | 2使用:

\n
op = Infix(lambda a, b: a + b)\n(1 | op)\n#<__main__.Infix object at 0x7facf8f33d30>\n\n# (op | 2)\n# TypeError: <lambda>() missing 1 required positional argument: \'b\'\n\n(1 | op | 2)\n# 3\n
Run Code Online (Sandbox Code Playgroud)\n
\n

绑定实施

\n

为了获得正确的绑定,需要编写一些更复杂的代码来执行中间绑定

\n
class Infix(object):\n    def __init__(self, func):\n        self.func = func\n\n    class RBind:\n        def __init__(self, func, binded):\n            self.func = func\n            self.binded = binded\n        def __call__(self, other):\n            return self.func(other, self.binded)\n        __ror__ = __call__\n\n    class LBind:\n        def __init__(self, func, binded):\n            self.func = func\n            self.binded = binded\n        def __call__(self, other):\n            return self.func(self.binded, other)\n        __or__ = __call__\n\n    def __or__(self, other):\n        return self.RBind(self.func, other)\n\n    def __ror__(self, other):\n        return self.LBind(self.func, other)\n\n    def __call__(self, value1, value2):\n        return self.func(value1, value2)\n
Run Code Online (Sandbox Code Playgroud)\n

使用方式与以前相同,例如:

\n
op = Infix(lambda a, b: a + b)\n
Run Code Online (Sandbox Code Playgroud)\n

或作为装饰器:

\n
@Infix\ndef op(a, b):\n    return a + b\n
Run Code Online (Sandbox Code Playgroud)\n

这样,人们就会得到:

\n
1 | op\n# <__main__.Infix.LBind object at 0x7facf8f2b828>\n\nop | 2\n# <__main__.Infix.RBind object at 0x7facf8f2be10>\n\n1 | op | 2\n# 3\n
Run Code Online (Sandbox Code Playgroud)\n

还有一个 PyPI 包(我与它没有任何关系)基本上实现了这一点: https: //pypi.org/project/infix/

\n

时间安排

\n

顺便说一句,绑定解决方案似乎也稍微快一些:

\n
%timeit [1 | op | 2 for _ in range(1000)]\n\n# Non-binding implementation\n# 1000 loops, best of 3: 626 \xc2\xb5s per loop\n\n# Binding implementation\n# 1000 loops, best of 3: 525 \xc2\xb5s per loop\n
Run Code Online (Sandbox Code Playgroud)\n

笔记

\n

这些实现使用|,但可以使用任何二元运算符:

\n
    \n
  • +:__add__
  • \n
  • -:__sub__
  • \n
  • *:__mul__
  • \n
  • /:__truediv__
  • \n
  • //:__floordiv__
  • \n
  • %:__mod__
  • \n
  • **:__pow__
  • \n
  • @:(__matmul__适用于 Python 3.5 及以上版本)
  • \n
  • |:__or__
  • \n
  • &:__and__
  • \n
  • ^:__xor__
  • \n
  • >>:__rshift__
  • \n
  • <<:__lshift__
  • \n
\n

**将需要绑定实现或调整非绑定实现以反映运算符是右关联的。上面的所有其他运算符要么是左结合的-, /, //, %, @, >>, <<),要么是直接交换的(+, *, |, &, ^)。

\n

请记住,这些运算符都与普通 Python 运算符具有相同的优先级,因此,例如:

\n
(1 | op | 2 * 5) == (1 | op | (2 * 5)) != ((1 | op | 2) * 5)\n
Run Code Online (Sandbox Code Playgroud)\n