I have a parent class that is inherited by several children. I would like to initialize one of the children using the parent's @classmethod
initializers. How can I do this? I tried:
class Point(object):
def __init__(self,x,y):
self.x = x
self.y = y
@classmethod
def from_mag_angle(cls,mag,angle):
x = mag*cos(angle)
y = mag*sin(angle)
return cls(x=x,y=y)
class PointOnUnitCircle(Point):
def __init__(self,angle):
Point.from_mag_angle(mag=1,angle=angle)
p1 = Point(1,2)
p2 = Point.from_mag_angle(2,pi/2)
p3 = PointOnUnitCircle(pi/4)
p3.x #fail
You can override the subclass's
__new__
method to construct instances from the superclass's alternate constructor as shown below.Note that in
__new__
, the linepoint = Point.from_polar(1, angle)
cannot be replaced bypoint = super().from_polar(1, angle)
because whereasPoint
sends itself as the first argument of the alternate constructor,super()
sends the subclassPointOnUnitCircle
to the alternate constructor, which circularly calls the subclass's__new__
that calls it, and so on until aRecursionError
occurs. Also note that even though__init__
is empty in the subclass, without overriding__init__
in the subclass, the superclass's__init__
would automatically be called immediately after__new__
, undoing the alternate constructor.Alternatively, some object designs are simpler with composition than with inheritance. For example, you could replace the above
PointOnUnitCircle
class without overriding__new__
with the following class.If you try to write
__init__
like that, yourPointOnUnitCircle
has a different interface toPoint
(as it takesangle
rather thanx, y
) and therefore shouldn't really be a sub-class of it. How about something like:This keeps the interface the same, adds logic for checking the inputs to the subclass (once you've written it!) and provides a new class method to easily construct a new
PointOnUnitCircle
from anangle
. Rather thanyou have to write