您可以为 Python 中的重载运算符强加对象优先级吗? [英] Can you impose object precedence for overloaded operators in Python?

查看:68
本文介绍了您可以为 Python 中的重载运算符强加对象优先级吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有两个 Python 类,它们都定义了 add 和 radd 运算符重载,并且我将一个类的一个实例添加到另一个类的另一个实例中.选择的实现取决于添加项的顺序(Python 首先在 LHS 上查找 add 方法等).

我是否可以定义优先选择哪个对象的实现?例如,如果 radd 的优先级高于 LHS,我希望在 RHS 上调用该 radd.

我真的很想为所有重载的运算符执行此操作,因此我最终想要一个更通用的解决方案.

例如,我可能有一个自定义数字类型类,我可能希望将 int 静默地类型转换为我的自定义类型.因此,我需要 add 和 radd(以及所有其他运算符重载及其r"表亲).

接下来,我想要一个通用多项式类,其系数是某种通用数字类型.我还想将事物类型转换为多项式,因此我为它实现了 add 和 radd 函数.但是,如果我在左侧添加一个自定义数字并在右侧添加一个多项式,我希望它被up 类型转换为多项式,而不是 Python 尝试将其类型转换 down 到自定义数字类型.因此,我希望调用 radd 而不是 add.

解决方案

没有内置机制来定义您所描述的优先级".您可以做的是在魔术方法中实现优先级检查.也就是说,您可以定义对象的 __add__ 方法,以便它检查另一个对象的优先级"(无论它是如何定义的),并调用该对象的 __add__(或 __radd__) 如果它的优先级更高.

请注意,如果您只希望 LHS __add__ 遵循 RHS __radd__,您可以返回 NotImplemented,这实际上会告诉 Python就好像你刚刚调用的 __add__ 方法不存在一样".

以下是如何使用魔术方法的装饰器完成此操作的草图:

def deco(op):def newOp(self, other):如果 other.precedence >自我优先:返回 NotImplemented返回操作(自己,其他)返回新操作类事物(对象):优先级 = 0def __init__(self, val):self.val = val@decodef __add__(self, other):打印 "Called", self, "__add__"返回 self.__class__(self.val + other.val)def __radd__(self, other):打印 "Called", self, "__radd__"返回 self.__class__(self.val + other.val)类弱(事物):优先级 = 1类强(事物):优先级 = 2

这导致 Strong 版本总是被调用而不管操作数的顺序如何,所以它总是返回一个 Strong:

<预><代码>>>>弱(1) + 强(1)调用 <__main__.Strong object at 0x01F96BF0>__radd__<__main__.Strong object at 0x01F96BD0>>>>强(1) + 弱(1)调用 <__main__.Strong object at 0x01F96B90>__添加__<__main__.Strong object at 0x01F96250>

Say I have two Python classes which both define the add and radd operator overloads, and I add one instance of one class to another instance of another class. The chosen implementation depends on the order in which the items are added (Python looks for an add method on the LHS first, etc).

Is it possible for me to define a precedence on which object's implementation is preferred? I want, for example, that radd is called on the RHS if its precedence is higher than that of the LHS.

I really want to do this for all overloaded operators, so a more general solution is what I'm eventually after.

[edit: added example]

For example, I may have a custom number type class, and I might wish to silently typecast ints to my custom type. Hence I need add and radd (and all the other operator overloads with their 'r' cousins).

Next, I want a generic polynomial class, whose coefficients are some generic number type. I also want to typecast things to polynomials, so I implement add and radd functions for it. However, if I add a custom number on the left with and a polynomial on the right, I want it to be typecast up to a polynomial instead of Python trying to typecast it down to a custom number type. Hence, I want radd to be called instead of add.

解决方案

There's no builtin mechanism for defining a "precedence" as you describe. What you could do is implement the precedence checking yourself within the magic methods. That is, you could define the object's __add__ method so that it checks the "precedence" of the other object (however that's defined), and calls that object's __add__ (or __radd__) if its precedence is higher.

Note that, if you just want the LHS __add__ to defer to the RHS __radd__ you can return NotImplemented, which will essentially tell Python "act as if the __add__ method you just called didn't exist".

Here is a sketch of how this could be done with a decorator on the magic methods:

def deco(op):
    def newOp(self, other):
        if other.precedence > self.precedence:
            return NotImplemented
        return op(self, other)
    return newOp

class Thing(object):
    precedence = 0

    def __init__(self, val):
        self.val = val

    @deco
    def __add__(self, other):
        print "Called", self, "__add__"
        return self.__class__(self.val + other.val)

    def __radd__(self, other):
        print "Called", self, "__radd__"
        return self.__class__(self.val + other.val)

class Weak(Thing):
    precedence = 1

class Strong(Thing):
    precedence = 2

This results in the Strong version always being called regardless of the order of operands, so it always returns a Strong:

>>> Weak(1) + Strong(1)
Called <__main__.Strong object at 0x01F96BF0> __radd__
<__main__.Strong object at 0x01F96BD0>
>>> Strong(1) + Weak(1)
Called <__main__.Strong object at 0x01F96B90> __add__
<__main__.Strong object at 0x01F96250>

这篇关于您可以为 Python 中的重载运算符强加对象优先级吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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