It has just dawned on me that I can set an attribute of a child class that only it's parent uses
In [34]: class A:
...: def __init__(self):
...: pass
...:
...: def a(self):
...: print(f'b = {self.b}')
...:
...: class B(A):
...: def __init__(self):
...: super(B, self).__init__()
...: self.b = 1
...:
In [35]: b = B()
...: b.a()
b = 1
This implementation seems counterintuitive and something feels wrong about it but I'm not quite sure what it is.
I would think that the following makes more sense
In [38]: class A:
...: def __init__(self, b):
...: self.b = b
...:
...: def a(self):
...: print(f'b = {self.b}')
...:
...: class B(A):
...: def __init__(self):
...: super(B, self).__init__(1)
...:
In [39]: b = B()
...: b.a()
b = 1
Are there use cases where the former would be a more recommended implementation than the latter?
Conceptually, you are doing two different things. In the first case, you have something like an abstract class; in other words, a base class which is not meant to be instantiated alone, because the definitions of certain attributes are "missing"; it is understood that subclasses will implement those attributes.
The more idiomatic way to do something like this would be to mark A
as an abstract base class using the abc
module, for example:
from abc import ABCMeta, abstractmethod
class A(metaclass=ABCMeta):
@property
@abstractmethod
def x(self):
pass
def print_me(self):
print(f'x = {self.x}')
class B(A):
@property
def x(self):
return 1
A().print_me()
The output will then be:
TypeError: Can't instantiate abstract class A with abstract methods x
On the other hand, this works:
B().print_me() # prints x = 1
By doing this, you signal clearly that a subclass must override the x
property, otherwise the print_me
function won't work.
Moving to the second case, you have a concrete base class and subclass, with the subclass acting something like a constraint on the nature of instances that can be created. In this case, a standalone instance of A
is perfectly valid; it is just that instances of B
provide the additional guarantee that a specific attribute will always be a certain value (or, at least, be initialised to a certain value, if you intend your class to be mutable).