Reputation: 110592
I would like to create a base class that has properties that all the children inherit, and also has a descriptive __repr__
method. Does the following seem like an acceptable implementation of this?
from collections import Counter
class Component:
cnt = Counter()
def __init__(self, _type, **kwargs):
Component.cnt[_type] += 1
self.type = _type
self.identifier = f'{self.type[0]}{Component.cnt[_type]}'
self._kwargs = kwargs
def __repr__(self):
s = f'{self.__class__.__name__}('
for k, v in self._kwargs.items():
s += f'{k}={v!r}, '
s = s.strip(', ') + f') # identifier: {self.identifier}'
return s
class Battery(Component):
# outbound is positive terminal
def __init__(self, voltage):
super().__init__(self.__class__.__name__, voltage=voltage)
self.voltage = voltage
>>> b=Battery(9)
>>> b
Battery(voltage=9) # identifier: B1
Specifically, does the self._kwargs
seem like a hack? What might be a better way to do that? Or, is there a better, more pythonic way of doing the above than I'm currently doing?
Upvotes: 0
Views: 96
Reputation: 51162
It's not necessary to pass self.__class__.__name__
to super().__init__
- the superclass's __init__
method can access it directly, just the same as your __repr__
method can. So the self.type
attribute is redundant.
Here is a reasonable way to write __repr__
in the base class: instead of using your own _kwargs
attribute, you can use the object's own __dict__
. This includes the identifier
attribute, so you don't need to add that separately.
from collections import Counter
class Component:
cnt = Counter()
def __init__(self, **kwargs):
_type = self.__class__.__name__
Component.cnt[_type] += 1
self.identifier = _type[0] + str(Component.cnt[_type])
super().__init__(**kwargs) # co-operative subclassing
def __repr__(self):
return '{0}({1})'.format(
self.__class__.__name__,
', '.join(
'{0}={1!r}'.format(k, v)
for k, v in self.__dict__.items()))
class Battery(Component):
# outbound is positive terminal
def __init__(self, *, voltage, **kwargs):
self.voltage = voltage
super().__init__(**kwargs) # co-operative subclassing
Example:
>>> b = Battery(voltage=9) # keyword-only argument for co-operative subclassing
>>> b
Battery(voltage=9, identifier='B1')
I've labelled some of the code with comments about co-operative subclassing. In a class hierarchy, each __init__
method can take its arguments as keywords, and pass its **kwargs
to the super().__init__
method so that you don't have to write the same argument names multiple times in both classes.
It's also important to call super().__init__
even from your base class if you are using multiple inheritance. Even if you don't use multiple inheritance, this will invoke object.__init__
which has the neat effect of making sure there are no "unused" arguments that weren't handled by another __init__
method.
Upvotes: 2