PEP 584: why not also __sub__?

I read PEP 584 and I like it. I already thought in past that a + operator will be nice for dicts.

I think that it could be useful to add support also for the - operand. It could operate between a dict and a non-string, non-bytes iterator, in this way:

{"Sulla": "Marco", "Hicks": "Bill"} - {"Sulla": "Marò", 4: 7}
# {"Hicks": "Bill"}
{"Sulla": "Marco", "Hicks": "Bill"} - ["Hicks", "Carlin"]
# {"Sulla": "Marco"}

Py implementation will be:

def __sub__(self, subtrahend):
    try:
        iter(subtrahend)

        if isinstance(subtrahend, (str, bytes, bytearray)):
            raise TypeError()
    except Exception:
        raise TypeError("unsupported operand type(s) for -: '{klass1}' and '{klass2}'".format(
            klass1 = type(self).__name__, 
            klass2 = type(subtrahend).__name__
        ))

    return {k: v for k, v in self.items() if k not in subtrahend}

and

def __isub__(self, subtrahend):
    try:
        iter(subtrahend)

        if isinstance(subtrahend, (str, bytes, bytearray)):
            raise TypeError()
    except Exception:
        raise TypeError("unsupported operand type(s) for -: '{klass1}' and '{klass2}'".format(
            klass1 = type(self).__name__, 
            klass2 = type(subtrahend).__name__
        ))

    for k in subtrahend:
        try:
            del self[k]
        except KeyError:
            pass

Personally I’d object to - since IMHO it is quite easy to write an equivalent dict comprehension, which is always clearer on the intent:

new_d = {k: v for k, v in d1.items() if k in d2}

over

new_d = d1 - d2

All objections from PEP 584 would still apply to the minus operator, but in this case the only clear advantage is you can type less, since none of the practical advantages mentioned in the PEP apply:

  • There is no clear alternative to the plus operator → you can use comprehension instead of minus.
  • The plus operand has an analogy in list → there is no list.__sub__.

Well, also list.__add__ is simple to write:

new_l = [*l1, *l2]

About list.__sub__, it’s different. Sequences can have the same values in different positions. On the contrary, in maps the keys are unique, so __sub__ make sense.

If you read the PEP carefully, you’ll find the sentence:

Set difference - is also obvious and natural, and an earlier version of this PEP included it in the proposal.

It got edited out of the current PEP because it was turning into a distraction. So let’s not get distracted, OK? :slight_smile:

Well, what you cite is in What about the full set API? as a possible addition. Furthermore it does only propose another dict as subtrahend, while I proposed any non-string, non-bytes iterable. I also added examples and a py implementation.

Furthermore I’m against implementing the set API, since maps are not set and any other operation will be quite useless IMHO.

I draw your attention back to the words “and an earlier version of this PEP included it in the proposal”. Your title asked “What not also __sub__?”; I was pointing out that it had in fact been discussed. Have you read that discussion?

Yes, an old PEP included it, so my propose is to include it in this proposal too, instead of cite it only as a possible addition,without the other set API and also supporting iterables other than dict.