I have custom class that inherites from list
. CustomList
instances support subtraction between themselves and with regular lists
. The corresponding elements of the CustomLists/lists
are subtracted. If one of the CustomLists/lists
is shorter, the missing elements are considered as zeros.
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__
works as expected, but when first operand is list (and __rsub__
is called) - subsctraction works in reverse. Instead of operand1 - operand2
it does operand2 - operand1
.
For example:
[1, 2, 3] - CustomList([2, 4, 6])
sholud be CustomList([-1, -2, -3])
but I got CustomList([1, 2, 3])
instead.
Why does this happen?
__rsub__
is called when you do list - CustomList
, let's say L - myList
. when you define __rsub__
the way you did, you are returning the result of myList - L
. But subtraction is not commutative (a - b != b - a
).
My recommended solution is to overload the negation operator (__neg__
) to define what - myList
is. and then modify __rsub__
to return - self.__sub__(other)
.
Here is the full solution:
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]