I have two classes like the following:
class Super(object):
def __init__(self, arg):
self.arg = arg
def load(self):
# Load data from disk if available
try:
self.data = load_routine()
except IOError as e:
if e[0] == errno.ENOENT:
pass
else:
raise
class Sub(Super):
def __init__(self, arg2, *args, **kwargs):
super(Sub, self).__init__(*args, **kwargs)
self.arg2 = arg2
def load(self):
# Load files specific to superclass
super(Sub, self).load()
# Load data from disk if available
try:
self.data2 = another_different_load_routine(self.arg2)
except IOError as e:
if e[0] == errno.ENOENT:
pass
else:
raise
I hope the code is clear enough, and unless I missed something this should work for both classes by using it for example like: obj = Super(); obj.load().
However, I actually want the load method to be called automatically at the end of __init__(), but I am not sure on how to accomplish this. If I add self.load() at the end of __init__() for both classes the load() method of the subclass would be called twice, if try to create an instance of Sub, once from the superclass and once from the subclass.
If I instead put the call to self.load() only at the end of the init method of the superclass, it will only be called once but then the object hasn’t been initialized to contain the attributes it needs for loading.
What I do want, when instantiating Sub, is for it to initialize all attributes in __init__ for both super and subclass, and call load() for both super and subclass. Whether its in the order
Super -> __init__(), Super -> load(), Sub -> __init__(), Sub -> load()
or
Super -> __init__(), Sub -> __init__(), Super -> load(), Sub -> load()
is not important. How can I accomplish this?
The answer is the combination you failed to enumerate:
If you actually want to instantiate super (it’s not an abstract class) you need the
iftest in it’s init. Otherwise, you cannot get the in-order semantics you want with your current class structure and initialization scheme.Sub()will callSub.__init__, which will callSuper.__init__(before doing anything).Afterwards,
__init__onSubwill do it’s thing.Last,
Sub.__init__will callSub.load, which will callSuper.load(before doing anything), then do it’s own work.The “normal” way to do this would be
Without the
__init__methods callingloadat all. This is probably what I’d recommend if you really want to call up levels inloadas it is essentially a second set of__init__s.Edit: Read the comments about the failings in the previous two versions (and see the edits to see the older one). Here is another version, using a metaclass:
This has a different restriction: All subclasses can act perfectly normally, except they can’t call
Sub.__init__, by usingsuper().__init__(). I think it’s possible to remove this restriction but I don’t see how at this second without another layer of indirection somewhere.