I have a class parent and two subclasses child1(parent) and child2(parent) sort of like the following near code. (edited to more properly show that the parent class is doing something)
class parent(object):
name = None
def __init__(self,e):
# process the common attributes
name = e.attrib['name']
def __new__(cls,e):
if e.attrib['type'] == 'c1':
return child1(e)
elif e.attrib['type'] == 'c2':
return child2(e)
else:
raise
class child1(parent):
extra1 = None
def __init__(self,e):
super(e)
# set attributes from e that are specific to type c1
class child2(parent):
extra2 = None
def __init__(self,e):
super(e)
# set attributes from e that are specific to type c2
The goal is to be able to get the "right" class based on the value of the parameter. So if I can say obj = parent(element)
and obj
will be either child1
or child2
depending on what the value of element.attrib['type']
is.
The problem is that inside parent.__new__
, you're calling child1(e)
, while calls child1.__new__
, which finds the implementation in parent.__new__
and calls it with the same e
, which calls child1(e)
, which… so you get infinite recursion.
There are better ways to design this, but if you just want to fix your design, there are three options:
If you define __new__
in all of your subclasses, it won't fall through the parent.__new__
. You can do this in a single step by interposing an intermediate
class between parent
and childN
, so you only need intermediate.__new__
. Or use a mixin that they all inherit, or …
Get rid of the inheritance. Is there really any reason child1
is-a parent
here?
You seem to be looking for what in Smalltalk/ObjC terms is called a "class cluster", and you don't need the "visible face" of the cluster to be the base class in Python any more than you do in those languages.
For example:
class base(object):
pass
class parent(base):
def __new__(cls, e):
# same as before
class child1(base):
# etc.
In Python, you can even make parent
an ABC, and register
each childN
with it so you can use isinstance
and friends with it.
Finally, you can just catch the recursion by only handling __new__
on parent
, not its subclasses:
def __new__(cls, e):
if cls is not parent:
return super(parent, cls).__new__(cls)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With