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.
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.
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 :)