Python中的新运算符 [英] New operators in Python

查看:102
本文介绍了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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆