Why are set methods like .intersection() not supported on set-like objects?

533 views Asked by At

In Python 3.7, I'd like to calculate the intersection of two dictionaries' keys. To do this, I'd like to call the .intersection() method on their keys(), however it does not work.

.keys() produces a set-like object, however most set methods don't work on it. What works however is the extremely unknown bitwise operator overloads for set-like objects, like &.

m = {'a':1, 'b':2}
n = {'b':3, 'c':4}

m.keys().intersection(n.keys())  # Pythonic, but doesn't work

m.keys() & n.keys()  # works but not readable

set(m.keys()).intersection(set(n.keys()))  # works, readable, but too verbose

I find that the & overload on a set-like object is extremely rarely used and is not known by most programmers. Method names like .intersection() or .union() is self-documenting and definitely more Pythonic by this definition.

Why isn't it supported then? Even the documentation lists the & and .intersection() methods like aliases, not mentioning that only & is supported on set-like objects.

note: For some reason, in IPython the autocomplete lists .isdisjoin() as a method which is available on dict.keys(). Out of the 17 set methods, 1 is present.

2

There are 2 answers

0
Ashutosh Chapagain On

The format should be

set.intersection(*others)

where other is any iterable. m.keys() is dict_keys not a set so that won't work.

set(m.keys()).intersection(n.keys())

will work :)

0
ShadowRanger On

dict views only guarantee the API of collections.abc.Set, not to be equivalent to set itself:

For set-like views, all of the operations defined for the abstract base class collections.abc.Set are available (for example, ==, <, or ^).

So they're not claiming to match set, or even frozenset, just collections.abc.Set collections.abc.Set doesn't require any of the named methods aside from isdisjoint (which has no operator equivalent).

As for why collections.abc.Set doesn't require the named methods, it may be because they are somewhat more complex (most take varargs, and the varargs can be any iterable, not just other set-like things, so you can, for example, intersection with many iterables at once), and they may have wanted to limit the complexity required to implement new subclasses (especially virtual subclasses, that wouldn't inherit any of the methods collections.abc.Set might choose to provide).

All that said, I generally agree with your point that it seems needlessly inconsistent to omit the method forms. I'd recommend you open a bug on the Python bug tracker requesting the change; just because it only guarantees Set compatibility doesn't mean it can't do more.