I’m having an issue trying to make a rectangle class that is subclassed from a Points class, which (bare with me) is subclassed from nd.array.
I’m aware (or so I think) of the nuances of subclassing an nd.array. What i’m trying to achieve is being able to construct a rectangle with a center point, height, width, and rotation and not need to directly feed in discrete points. Below is my implementation of the rectangle constructor, the @init_args wrapper takes type hinted inputs and calls the class constructor which works. It appears that it isn’t even getting into the
__init__ method and jumps straight to the Points
class Points(np.ndarray): def __new__(cls, list_of_points): if type(list_of_points) == 'numpy.ndarray': obj = list_of_points else: obj = np.vstack(list_of_points).view(cls) return obj class Rectangle(Points): @init_args def __init__(self, rect_attributes: RectAttributes): self.points = np.zeros((4, 2)) print('in rect constructor') self.attributes = rect_attributes self.construct_rect_from_attributes() super().__init__(self.points)
I don’t think I really need the
super().__init__ call, I was just hoping that it would delay the Points constructor. What I really need is just to be able to initialize the rectangle with attributes that aren’t contained in the superclass.
The comment of chepner is make sense. Another thing that’s confusing to me as that you want
Rectangle to be a subclass of
ndarray, yet you assign to it a
self.points (initialized to zeros) of a different ndarray.
ndarray.__new__ itself constructs the array and its data, so your
Rectangle class is essentially already constructed from the
list_of_points passed to
Meanwhile you have a
self.points that has no association with the points passed to the constructor.
From your example it’s not clear what
rect_attributes is supposed to be or what
construct_rect_from_attributes() is supposed to do. But I think what you probably want is something like this (and IMO you should allow construction of
Rectangle from a list of points as well, but that’s up to whatever your requirements are):
class Rectangle(Points): # put in the type hints anything else array-like def __new__(cls, data: Union[list, np.ndarray, RectAttributes]): if isinstance(data, RectAttributes): # assuming you want to store the original attributes somewhere self.attributes = data # rect_from_attributes should be a classmethod and # should return an array of points data = cls.rect_from_attributes(data) else: # a default value if the rect was constructed another # way, or inversely construct a RectAttributes from points self.attributes = ... return super().__new__(cls, data)