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. -- Steven