[How]Should I document constructor arguments that are essentially removed/constant in subclasses? e.g. I have a class like
def __init__(self, bar: bool):
self.bar = bar
There are also a variety of subclasses, e.g.
MoreSpecificFoo that require
bar to be
False. If I understand Liskov substition, type variance, PEP 483, and the principle of least surprisal correctly, I ought to keep the
bar param in the constructor, add guard code when it’s set to the wrong value, and document that the arg must be false (default) but is retained for supertype compatibility.
That seems like a lot of unneccessary code, when all I really want is to just set
self.bar = False in the constructor. Especially if there are different types of more specific Foos that all require
bar=False. Are all those extra lines really best practice?
I personally would call
super().__init__(bar=False) and not have the subclass’s constructor accept the argument at all. Practicality beats purity.
Constructors aren’t, in the literature I’ve read, normally considered part of the interface (i.e. expected to heed LSP). After all, many class designs treat the constructor as being for internal use only and expect the client to use some kind of factory. (This is useful for classes that need to be able to make modified copies of themselves, but can reach states that aren’t easily expressible in terms of the constructor arguments.)
Speaking of: the enterprise solution here - assuming that
bar is supposed to be immutable (if not, why does its value at construction matter?) - is to have
FooWithFalseBar direct subclasses, give the base class an abstract factory instead (perhaps using
FooWithFalseBar, and eliminate the
bar attribute. (Classes that previously could use either value of
bar become split into separate true and false versions, of course.)