Reputation: 115
I want to overwrite some default class attributes in inherited classes, which influence the functionality of intermediate classes.
e.g. in the following snippet, in the intermediate Child
's initialisation, I want the call to internal_setting
to rely on _a
as set by GrandChild
, so that the outputs are both that
.
class Parent():
def __init__(self):
# set a basic parameter
self._a = True
def externally_called_method(self):
# uses correct self._a
if self._a:
self.externally_set = "this"
else:
self.externally_set = "that"
class Child(Parent):
def __init__(self):
super().__init__()
self.internal_settings()
def internal_settings(self):
# uses most recent self._a
if self._a:
self.internally_set = "this"
else:
self.internally_set = "that"
class GrandChild(Child):
def __init__(self):
super().__init__()
self._a = False
g = GrandChild()
g.externally_called_method()
print("Internally set: {}".format(g.internally_set))
print("Externally set: {}".format(g.externally_set))
>>> Internally set: this
>>> Externally set: that
Is it possible that methods called by the __init__
of an intermediate (Child
) class uses the attribute of the GrandChild
class?
I know I could just make _a
a param, but I prefer not to since in the real program, the Parent
class has a large number of attributes which can be overwritten by subclasses.
A secondary question is whether this is a bad approach in general, i.e. facilitating customisation by a ladder of inherited classes, where attributes can be set according to the use-case.
Upvotes: 0
Views: 1706
Reputation: 110166
Once you are running a method, it will run thoughtfully - if Parent.__init__
is called to initialize parameters, and it is called from Child.__init__
, there is no way you can change that from GrandChild.__init__
: it can, obviously, just run Child.__init__
as a single call.
However, if you break you classes in more components, that is easily fixable.
If the parameters can be class attributes, it is as easy as just declaring them outside __init__
, and the natural inheritance rules of O.O. will work for you:
class Parent():
_a = True
def __init__(self):
# basic parameters are set as class attributes.
...
...
class GrandChild(Child):
_a = False
def __init__(self):
super().__init__()
If they can't be straight class attributes (due to needing from runtime input that is passed to __init__
, all you have to do is to break-up the responsibilities of your class in more methods (one can call these methods "slots") so, __init__
instead of having the responsibility to initialize all parameters, then call the internal_settings
- can instead delegate the responsibility of initializing the parameters to another method. In that way, you can override that method on the GrandChild:
class Parent():
def __init__(self):
self._set_parameters()
def _set_parameters(self):
self._a = True
def externally_called_method(self):
# uses correct self._a
if self._a:
self.externally_set = "this"
else:
self.externally_set = "that"
class Child(Parent):
def __init__(self):
super().__init__()
self.internal_settings()
...
class GrandChild(Child):
def __init__(self):
super().__init__()
def _set_parameters(self):
self._a = False
And, of course, your problem is more complicated than this - but all you have to do is to move all initialisations or tasks that could be individually overriden to separate methods - in that way you just replace any setup as needed in the child classes.
Upvotes: 1