Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Method to convert object from class to subclass in Python

Consider the following minimal problem:

from math import sqrt    

class Vector(object):

    def __init__(self, x, y, z):
        self.v = [x, y, z]

    def normalize(self):
        x, y, z = self.v
        norm = sqrt(x**2 + y**2 + z**2)
        self.v = [x/norm, y/norm, z/norm]

    # other methods follow  

class NormalizedVector(Vector):

    def __init__(self, x, y, z):
        super(Vector, self).__init__(x, y, z)
        self.normalize()

So essentially NormalizedVector objects are the same as Vector objects but with the added normalization.

Would it be possible to add a method to Vector so that whenever the normalize method is called the object is automatically subclassed to NormalizedVector?

I know that I could be using the abstract factory pattern, but this would only work if objects are subclassed at creation: I would like to be able to subclass objects that have already been created previously.

I have found some solutions based on reassigning the __ class __ method, but these are discouraged. I am willing to modify the pattern above to a one that it is more "Pythonic".

like image 761
Daniel Arteaga Avatar asked May 16 '26 20:05

Daniel Arteaga


1 Answers

I would recommend to use only the Vector() class and with a boolean normalized instance attribute.

Also, in normalize method you are using x, y and z but those variables are not defined and you are not even reading them with self.

The code I would recommend:

from math import sqrt    

class Vector(object):

    def __init__(self, x, y, z, normalized=False):
        self.v = [x, y, z]
        if normalized in [True, False]:
            self.normalized = normalized
        else:
            raise Exception("Please set normalized to either True or False")

    def __repr__(self):
        return "Vector ({}, {}, {})".format(*self.v)

    def normalize(self):
        x,y,z = self.v
        norm = sqrt(x**2 + y**2 + z**2)
        self.v = [x/norm, y/norm, z/norm]
        self.normalized = True

    def isNormalized(self):
        return self.normalized

    # other methods follow  

v1 = Vector(10, 20, 30)
print v1.isNormalized()
v1.normalize()
print v1.isNormalized()

v2 = Vector(40, 50, 60, normalized=True)
print v2.isNormalized()

Output:

False
True
True


The __repr__ function will just show a good representation of your object:

print v1

Output:

Vector (0.267261241912, 0.534522483825, 0.801783725737)
like image 76
Andrés Pérez-Albela H. Avatar answered May 19 '26 11:05

Andrés Pérez-Albela H.