
On Wed, Oct 27, 2021 at 10:40 AM Christopher Barker <pythonchb@gmail.com> wrote:
subclassing and defaults.
There is one use case I'm not sure how to wrap my head around.
Say a class and subclass have different default arguments. And we want to pass the fact that the argument wasn't set along to the superclass. The "use None" convention works fine:
def __init__(self, something=None): super().__init__(something)
The superclass could define its own default.
But deferred binding would not work:
def __init__(self, something=an_expression): super().__init__(something)
The superclass would get the result of an_expression, and not know that it should use its default.
Is this an actual problem? I'm not sure -- I can't think of when I wouldn't want a subclass to override the default of the superclass, but maybe ? And of course, if you really do need that, then use a sentinel in that case :-) No one's suggesting that every default should be specified explicitly!
Hmm. Trying to figure out what this would mean in practice. Let's get some concrete names for a moment. class Pizza: def __init__(self, cheese="mozzarella"): ... class WeirdPizza(Pizza): def __init__(self, cheese="brie"): # you monster ... Pizza("cheddar") # Legal, makes a cheddar pizza WeirdPizza("cheddar") # Legal, makes a cheddar weirdpizza Pizza() # Standard pizza WeirdPizza() # Nonstandard pizza If you're overriding the default, then you definitely want to use the subclass's default. So in this simple case, no problem. Another case is where you're trying to specify that the subclass should retain the superclass's default. But in that sort of situation, you probably want to retain ALL unspecified defaults - and that's best spelled *a,**kw, so that's fine too. All I can think of is that you want to replace some, but not all, of the defaults. That'd be a bit clunky, but if your API is complicated like that, it should probably be made entirely kwonly for safety, which means you can write code like this: def __init__(self, *, tomato="ketchup", **kw): super().__init__(self, tomato=tomato, **kw) A little clunky, but it lets you change one default, while keeping others with the same defaults. It would be nice to have a way to daisy-chain function signatures (think like functools.wraps but merging the signatures), but that would be quite a big thing to try to build. Would be an interesting idea to tackle though. ChrisA