On Wed, Oct 27, 2021 at 10:40 AM Christopher Barker <python...@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
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/QP6NAPECPO42VAGIC7IGKWUKAZHZHA3F/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to