I would like to implement the following structure:
class Case(nx.Graph):
def __init__(self, case):
if case == 1:
self = Case1()
if case == 2:
self = Case2()
class Case1(Case):
def __init__(self):
super(Case1, self).__init__()
print "Case1"
class Case2(Case):
def __init__(self):
super(Case2, self).__init__()
print "Case2"
For instance, if I create the following object:
graph = Case(1)
a new Object of the class Case1 should be created. In the __init__ of the class Case1 the super() fuction should call the __init__ function of the networkx.Graph().
If I run that code, the result should be a networkx.Graph object called "graph" and it should print Case1.
3 Answers 3
When you say self = ..., you are just redefining self. You aren't changing it. To do what you want, use __new__ instead:
class Case(nx.Graph):
def __new__(self, case):
if case == 1:
return Case1()
elif case == 2:
return Case2()
else:
raise ValueError("Invalid argument")
You really shouldn't do this, though. If you want a different instance for a different case, do it when you create the instance, but a class should not depend on its children in order to work.
3 Comments
Case1 inherits from Case and thus also has this __new__-method.x = Case1(), not x = Case(1). It gets buggy when you try to do it this way. For one thing, since Case1 and Case2 inherit from Case, you would still need to do x = Case1(1) because __new__ needs that argument. It just gets really buggy when you make a parent class depend on its children.One way of doing it is by not invoking __init__ for the subclasses but putting these in a seperate method, i.e. setup and rewriting the __class__ attribute:
class Case(object):
def __init__(self, case):
# Maybe even call the init of the superclass:
super(Case, self).__init__()
# Do the setup that is common to all Cases:
self.setup()
# Change the class of the instance depending on your case:
if case == 1:
self.__class__ = Case1 # No () here!
elif case == 2:
self.__class__ = Case2
else:
raise ValueError()
# Call the setup of the subclass
self.setup()
def setup(self):
print('Setup of Case called.')
class Case1(Case):
def setup(self):
print('Setup of Case1 called.')
class Case2(Case):
def setup(self):
print('Setup of Case2 called.')
when I try to create a Case1:
a = Case(1)
it prints:
Setup of Case called.
Setup of Case1 called.
But there might even be proper (builtin-modules, packages) recipes for doing something like this.
Comments
This is a classic Factory pattern. I would implement it using a static method as follows:
class Case(object):
@staticmethod
def factory(case):
if case == 1:
return Case1()
if case == 2:
return Case2()
raise NotImplementedError('Unknown case: %r'%case)
class Case1(Case):
def __init__(self):
super(Case1, self).__init__()
print "Case1"
class Case2(Case):
def __init__(self):
super(Case2, self).__init__()
print "Case2"
You can extend as appropriate for args to pass to the initializer. IN usage, you might see something like the following:
c1 = Case.factory(1)
c2 = Case.factory(2)
print type(c1), type(c2)
Case.factory(3)
Output would look like this:
Case1
Case2
<class '__main__.Case1'> <class '__main__.Case2'>
Traceback (most recent call last):
File "<string>", line 36, in <module>
File "<string>", line 19, in factory
NotImplementedError: Unknown case: 3
case = Case(x), you expect to get an instance ofCase, not any other class. Have plainCase1andCase2classes, even if they inherit from a common parent, and leave the decision which class to construct outside any of those classes.Class.__init__is only called on a new object ifClass.__new__actually returns an instance ofClass.