在 __add__ 运算符中返回相同子类的对象

Posted

技术标签:

【中文标题】在 __add__ 运算符中返回相同子类的对象【英文标题】:Returning object of same subclass in __add__ operator 【发布时间】:2013-05-20 22:38:09 【问题描述】:

我正在为自己的解释器开发一个简单的类型系统。 我正在写这样的东西:

class Base(object):
    def __init__(self, content):
        self.__content = content

    @property
    def content(self):
        return self.__content

    @content.setter
    def content(self, value):
        self.__content = value

class Number(Base):
    def __init__(self, content):
        super(Number, self).__init__(content)

    def __add__(self, other):
        return Number(self.content + other.content)

    ...and so on

class Float(Number):
    def __init__(self, content):
        super(Float, self).__init__(content)

class Integer(Number):
    def __init__(self, content):
        super(Integer, self).__init__(content)

我的问题显然是如果我这样做:

if __name__ == '__main__':
    f1 = Float(3.5)
    f2 = Float(2.3)
    f3 = f1 + f2
    type(f3)

我将f1和f2相加,它们是Float类型,但我得到了f3,它是Number类型,但我希望f3是Float类型。如何在 Number 超类中定义一次 add 运算符,返回一个与 f1 和 f2 相同的类型?我必须使用 isinstance 吗?有没有更清洁的方法来做到这一点?

谢谢!

【问题讨论】:

【参考方案1】:

你可以用__class__做点什么:

def __add__(self, other):
    return self.__class__(self.content + other.content)

正如@Eric 指出的那样,你可能想做一些类似

的事情
if self.__class__ == other.__class__:
    <use __class__>
else:
    <use Number>

以确保可预测的行为(或在类不匹配时采取其他行动)。

__radd__ 也值得在这里覆盖:

__radd__ = __add__

这将使Number(1) + Float(1) == Float(1) + Number(1) == Float(2)

【讨论】:

你可能需要仔细考虑是要self.__class__还是other.__class__ 哦,谢谢。它完美地工作。我以为 Number 类中的 self.__class__ 会等于 'Number'...我错了。 为了进一步扩展,我想你想要(1, 0): self.__class__, (0, 1): other.__class__.get((issubclass(self.__class__, other.__class__), issubclass(other.__class__, self.__class__)), Number)。如果我不必将它放在评论中,那将不那么迟钝。 实际上,放弃它。只要别名__radd__,python 会处理好事情 @Eric,请随时将其编辑到我的答案中,因为那里会更清楚。

以上是关于在 __add__ 运算符中返回相同子类的对象的主要内容,如果未能解决你的问题,请参考以下文章

重载 __eq__ 以返回自定义对象

Python 运算符重载中__add__(self,other)的other.x如何理解?

python 基础之算数运算

运算符重载

类的运算符

Python面向对象运算符重载