'How to make the class constructor that returns the object of child class?
I'm coding in Python. I have a Base
class which contains several methods. There are some child classes; they may have their own methods. I want the Base
class constructor to create the object not of the class itself but the object of one of the child classes depending on the argument.
For example, guess our child classes are Point
, Line
, and Plane
, all are inherited from Base
, and the difference between them is set by the dim
attribute of the Base
class.
class Base():
def __init__(self, dim, a, b):
self.dim = dim
self.a = a
self.b = b
class Point(Base):
def __init__(self, a, b):
super().__init__(1, a, b)
class Line(Base):
def __init__(self, a, b):
super().__init__(2, a, b)
class Plane(Base):
def __init__(self, a, b):
super().__init__(3, a, b)
If I explicitly create a Point
, the object type will be Point
:
pointA = Point(0, 0)
type(pointA) # __main__.Point
But if I do the same through the Base
constructor, the object will be of class Base
:
pointB = Base(1, 0, 0)
type(pointB) # __main__.Base
So I'd like to change this behavior and make the Base
constructor return a Point
, Line
or Plane
object if the dim
attribute is equal to 1, 2 or 3 respectively. How can I do this?
EDIT:
Based on this thread (Improper use of __new__ to generate class instances?) I overrid the Base.__new__()
and got the following code:
class Base():
def __new__(cls, a, b, dim):
if dim == 1:
return object.__new__(Point)
elif dim == 2:
return object.__new__(Line)
elif dim == 3:
return object.__new__(Plane)
class Point(Base):
def __init__(self, a, b, dim):
self.a = a
self.b = b
class Line(Base):
def __init__(self, a, b, dim):
self.a = a
self.b = b
class Plane(Base):
def __init__(self, a, b, dim):
self.a = a
self.b = b
The code above works, but it requires an explicit setting of the dim
argument even when I create a new Point
instance. A non-identical set of arguments in Base.__new__()
and Point.__init__()
raises an error. How can I keep this behavior but remove dim
from the Point
constructor?
Solution 1:[1]
You don't typically want to do this by instantiating a base case. While I suppose you could override __new__
, I wouldn't advise it for this. Notably, though, __init__
has a None return type. So, regardless, you can't do this in __init__
- the object is already created at that point.
Instead, what you probably want is a static so-called 'Factory' method on your base class:
from typing import Type
class Base():
@staticmethod
def create(dim, a, b) -> Type[Base]:
# Decide which subclass you want to create, instantiate and return it.
...
new_obj = Base.create(x, y, z)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |