>  construction calls __init__ if __new__ returns an instance

Actually type's __call__ method does that, although that doesn't help my point at all...

Your point about there being no method to perform the dispatch is good.  To get what I want without interpreter changes there would need to be some sort auxiliary getitem method which would perform the protocol.  Or alternatively MissingMapping (or some other mixin) could define __getitem__ and  require __getitem_impl__ and __missing__.  As this wouldn't require any changes to anything I think it might be the best solution I have proposed.

>  I don't see how this is much different from what dicts already do. 

I was suggesting making __missing__ part of what a subscript expression in a load context (__getitem__) means so that user defined Mappings could use it.

I've gotten fairly off topic I might make a new thread for my idea.


On Wed, Apr 15, 2020 at 6:35 PM Steven D'Aprano <steve@pearwood.info> wrote:
On Mon, Apr 13, 2020 at 06:43:53PM -0700, Caleb Donovick wrote:

> > Why can’t you just subclass dict and override that?
> Because TypeError: multiple bases have instance lay-out conflict is one of
> my least favorite errors.

For the benefit of the people on this list who aren't as familiar with
your code as you are, could you explain how that comment is relevant?

I don't like "multiple bases have instance lay-out conflict" errors
either. But I don't get them from subclassing dict.

    py> class MyDict(dict):
    ...     def __missing__(self, key):
    ...             return (key, None)
    py> MyDict()[999]
    (999, None)

Works fine.

Normally, if I get that error, it's a sign that I'm probably using too
much multiple inheritence and not enough composition, or even that I
should step away from from the OO paradigm and reconsider whether or not
I actually need a hybrid list+float object :-)

So can you please explain why how this exception is relevant, and how
the proposal here will fix it?

defaultdict is subject to the same "lay-out conflict" issue, so from my
naive point of view, this proposal won't help you avoid the error.

    py> from collections import defaultdict
    py> class Weird(int, defaultdict):
    ...     pass
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: multiple bases have instance lay-out conflict

> Perhaps `__missing__` could be a first class part of the getitem of
> protocol, instead of a `dict` specific feature.  So that
> ```
> r = x[key]
> ```
> means:
> ```
> try:
>   r = x.__getitem__(key)
> except KeyError as e: # should we also catch IndexError?
>   try:
>     missing = x.__missing__
>   except AttributeError:
>     raise e from None
>   r = missing(key)
> ```

I don't see how this is much different from what dicts already do. You
can't add a `__missing__` attribute to literal dicts (or lists, tuples,
etc) since they don't take attributes.

    {}.__missing__ = lambda key: key

fails, so you have to subclass anyway.

> Obviously this would come at some performance cost for non dict mappings so
> I don't know if this would fly.

Giving every single dict a `__missing__` member, for the sake of the
rare instance that needs one, would come at a performance and memory
cost too.

It would be nice if we could work out what the problem we are trying to
solve is before we jump straight into solutions mode.

To my mind, the naive problem "if `d[key]` fails, call a method with
`key` as argument" already has a solution. If the `__missing__` dunder
isn't a solution, I don't know what the problem is.

Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-leave@python.org
Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/DF4TMSDTNOQ53VTESLT3I4DZFPNEXBVE/
Code of Conduct: http://python.org/psf/codeofconduct/