I want to define a class AorB, such that all A's are AorB's, and all B's are AorB's, and these are all the AorB's. Of course, A and B should be subclasses of AorB. The problem is in AorB.__init__
, when I can't convince self it should be something else. I can define an AorB factory, but I'd rather have AorB constructor if possible.
class AorB:
def __init__(self,par):
if par: self=A(par) #!
else: self=B() #!
@staticmethod
def from_par(par):
if par: return A(par)
else: return B()
class A(AorB):
def __init__(self,par):
self.par=par
class B(AorB):
def __init__(self):
pass
print(
AorB.from_par(5),
AorB.from_par(0),
AorB(5),
AorB(0),
sep="\n")
I know assignment to self doesn't work here, but I just wanted to show intention. As I said, factory (from_par) works fine, I just want to call it as AorB
, not as AorB.from_par
.
PS. I know, __init__
is probably too late, type of self is already determined. Feel free to use metaclasses in your answer. It's time I learn something useful about them. :-)
You can't, not with __init__
. Once __init__
is being called, the instance is already created.
You want a factory function instead:
class AorB: pass
class A(AorB):
def __init__(self,par):
self.par=par
class B(AorB):
def __init__(self):
pass
def AorB(par):
return A(par) if par else B()
From an API point of view, there is no difference; AorB
is a callable that produces either an A()
or a B()
instance.
The other possible route involves defining a __new__
function instead; this is the class constructor:
class AorB:
def __new__(cls, par=None):
if cls is not AorB: return super().__new__(cls)
return super().__new__(A) if par else super().__new__(B)
class A(AorB):
def __init__(self, par):
self.par = par
class B(AorB):
def __init__(self, par=None):
pass
Which is just a more involved factory function, really. Note that the __new__
method returns the result of super().__new__
of one of the subclasses based on par
, so both A
and B
will be passed a par
parameter, wether they want one or not.
The if cls is not AorB
line is needed to allow instantiating A()
or B()
directly; you can omit that line if that is not a requirement and only the AorB
factory class is used.