为什么`__rsub__`要反向减?

问题描述 投票:0回答:1

我有继承自

list
的自定义类。
CustomList
实例支持它们之间的减法以及与常规
lists
的减法。减去
CustomLists/lists
的相应元素。如果
CustomLists/lists
之一较短,则缺失的元素将被视为零。

from typing import Iterable, List


class CustomList(list):
    def __init__(self, *args: Iterable[int | float]):
        if args == ():
            super().__init__(*args)
        elif all(isinstance(a, (int, float)) for a in args[0]):
            super().__init__(*args)
        else:
            raise TypeError("CustomList instance can contain int and float datatypes only")

    def __sub__(self, other: List[int | float] | "CustomList") -> "CustomList":
        if isinstance(other, (self.__class__, list)):
            result = CustomList()
            for i in range(max(len(self), len(other))):
                if i < len(self) and i < len(other):
                    result.append(self[i] - other[i])
                elif i < len(self):
                    result.append(self[i])
                else:
                    result.append(other[i])
            return result

    def __rsub__(self, other):
        return self.__sub__(other)

__sub__
按预期工作,但是当第一个操作数是列表时(并且调用
__rsub__
) - 减法则相反。它不是
operand1 - operand2
,而是
operand2 - operand1

例如:

[1, 2, 3] - CustomList([2, 4, 6])
应该是
CustomList([-1, -2, -3])
但我得到了
CustomList([1, 2, 3])
。 为什么会出现这种情况?

python operator-overloading
1个回答
0
投票
当您执行

__rsub__

 时,会调用 
list - CustomList
,比方说
L - myList
。当您按照您的方式定义
__rsub__
时,您将返回
myList - L
的结果。但减法不可交换 (
a - b != b - a
)。

我推荐的解决方案是重载否定运算符 (

__neg__
) 来定义
- myList
是什么。然后修改
__rsub__
返回
- self.__sub__(other)

这是完整的解决方案:

from typing import Iterable, List


class CustomList(list):
    def __init__(self, *args: Iterable[int | float]):
        if args == ():
            super().__init__(*args)
        elif all(isinstance(a, (int, float)) for a in args[0]):
            super().__init__(*args)
        else:
            raise TypeError("CustomList instance can contain int and float datatypes only")

    def __sub__(self, other: List[int | float] | "CustomList") -> "CustomList":
        if isinstance(other, (self.__class__, list)):
            result = CustomList()
            for i in range(max(len(self), len(other))):
                if i < len(self) and i < len(other):
                    result.append(self[i] - other[i])
                elif i < len(self):
                    result.append(self[i])
                else:
                    result.append(other[i])
            return result

    def __neg__(self):
        result = CustomList()
        for val in self:
            result.append(-val)
        return result

    def __rsub__(self, other):
        return - self.__sub__(other)
>>> [1, 2, 3] - CustomList([2, 4, 6])
[-1, -2, -3]
© www.soinside.com 2019 - 2024. All rights reserved.