I'm learning Python on my own and I found a task that requires using a decorator @dataclass to create a class with basic arithmetic operations.
from dataclasses import dataclass
from numbers import Number
@dataclass
class MyClass:
x: float
y: float
def __add__(self, other):
match other:
case Number():
return MyClass(float(other) + self.x, self.y)
case MyClass(ot_x, ot_y):
return MyClass(self.x + ot_x, self.y + ot_y)
__radd__ = __add__
I have implemented the addition operation. But I also need to do the operations of subtraction __sub__, multiplication __mul__, division __truediv__, negation __neg__, also __mod__ and __pow__. But I couldn't realize these operations. The main thing for me is to use the construction match/case. Maybe there are simpler ways to create it.
I will be glad of your help.
If you're trying to make a complete numeric type, I strongly suggest checking out the implementation of the
fractions.Fractiontype in thefractionssource code. The class was intentionally designed as a model for how you'd overload all the pairs of operators needed to implement a numeric type at the Python layer (it's explicitly pointed out in thenumbersmodule's guide to type implementers).The critical parts for minimizing boilerplate begin with the definition of the
_operator_fallbacksutility function within the class (which is used to take a single implementation of the operation and the pairedoperatormodule function representing it, and generate the associated__op__and__rop__operators, being type strict for the former and relaxed for the latter, matching the intended behavior of each operator based on whether it's the first chance or last chance to implement the method).It's far too much code to include here, but to show how you'd implement addition using it, I'll adapt your code to call it (you'd likely use a slightly different implementation of
_operator_fallbacks, but the idea is the same):By putting the ugliness of type-checking and coercion in common code found in
_operator_fallbacks, and putting only the real work of addition in_add, it avoids a lot of every-operator-overload boilerplate (as you can see here;_operator_fallbackswill be a page of code to make the forward and reverse functions and return them, but each new operator is only a few lines, defining the monomorphic operator and calling_operator_fallbacksto generate the__op__/__rop__pair.