Skip to content Skip to sidebar Skip to footer

Do I Have To Override All Math Operators In A Subclass?

I want to make a simple Point2d class in a Python 3.7 program that implements just a few features. I saw in an SO answer (that I can't find now) that one way to create a Point clas

Solution 1:

In this case I suggest to implement your class Point2d from scratch.

If you're lazy, take a look to some lib like sympy which includes a Point class and other geometry stuff https://docs.sympy.org/latest/modules/geometry/index.html

Solution 2:

The problem, is that your class, when it uses any of the data model functions belonging to complex It returns a complex, so you'll need to turn this in to your Point2d class

adding this method should do the trick

def__add__(self, b):
    return Point2d(super().__add__(b))

But still there should be a better way of doing it. But this is the way to dynamically wrap some Data Model (dunder) methods.

By the way, the distance function you can make it shorter something like this

defdistanceTo(self, otherPoint):
    returnabs(self - otherPoint)

Solution 3:

I'm going to mention a way of overriding all the methods without manually writing each of them, but only because we are all consenting adults here. I don't really recommend it, it is much clearer if you just override each and every operation. That said, you can write a class wrapper which inspects all the methods of the base class and converts the output to a point if it is a complex type.

import math
import inspect


defconvert_to_base(cls):
    defdecorate_func(name, method, base_cls):
        defmethod_wrapper(*args, **kwargs):
            obj = method(*args, **kwargs)
            return cls.convert(obj, base_cls) ifisinstance(obj, base_cls) else obj
        return method_wrapper if name notin ('__init__', '__new__') else method
    for base_cls in cls.__bases__:
        for name, method in inspect.getmembers(base_cls, inspect.isroutine):  # Might want to change this filtersetattr(cls, name, decorate_func(name, method, base_cls))
    return cls


@convert_to_baseclassPoint2d(complex):

    @classmethoddefconvert(cls, obj, base_cls):
        # Use base_cls if you need to know which base class to convert.return cls(obj.real, obj.imag)

    defdistanceTo(self, otherPoint):
        return math.sqrt((self.real - otherPoint.real)**2 + (self.imag - otherPoint.imag)**2)

    defx(self):
        return self.real

    defy(self):
        return self.imag

p1 = Point2d(3, 3)
p2 = Point2d(6, 7)
p3 = p1 + p2
p4 = p3.distanceTo(p1)
print(p4)

# 9.219544457292887

What is happening here is that it just checks all the methods of the base class, and if what it returns is of the type of the base class, converts it to the child class, as defined by the special classmethod in the child class.

Solution 4:

In general, prefer composition to inheritance. You can implement all the desired operations in terms of complex numbers.

classPoint2D:def__init__(self, x, y):
        self._p = complex(x,y)

    @classmethoddef_from_complex(self, z):
        return Point2D(z.real, z.imag)

    def__add__(self, other):
        return Point2D._from_complex(self._p + other._p)

    # etc

Is it a lot of boilerplate? Yes. But it's not really boilerplate you can avoid.

Post a Comment for "Do I Have To Override All Math Operators In A Subclass?"