How to return a subclass from __new__ parameter
python, python-2.7
Solution
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)
Problem
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.