[Python-ideas] Fwd: Why do equality tests between OrderedDict keys/values views behave not as expected?
Steven D'Aprano
steve at pearwood.info
Fri Dec 18 06:07:55 EST 2015
On Fri, Dec 18, 2015 at 02:38:53AM +0000, Andrew Barnert via Python-ideas wrote:
[...]
> > Anyway, this is all a moot point. *If* they were to do something
> > different from dict's views, then they should follow
> > OrderedDict.__eq__.
>
> Sure; any other option is terrible.
>
> In fact, both of these options are terrible--one breaks consistency
> with other mappings, and with the basic rules of comparison; the other
> breaks consistency with the other related types. Ick. Then again, they
> both have compelling arguments for them, and they're both pretty
> simple. I doubt anyone has any critical code that relies on the
> current behavior, but then I doubt anyone would write any critical
> code that relied on the other behavior if it were changed.
This thread has wandered over a fair bit of ground, so I've lost track
of *precisely* what these options are. I think we're still debating the
fact that OrderedDict *values* compare by ID (like arbitrary objects),
rather than by value like items and keys.
For example:
py> from collections import OrderedDict as odict
py> a = odict([('a', 1), ('b', 2)])
py> b = a.copy()
py> a.keys() == b.keys()
True
py> a.items() == b.items()
True
So KeysView and ItemsView compare by the value of the view. But
ValuesView compare by ID, not value:
py> a.values() == b.values()
False
This makes no sense to me. The same counter-intuitive behaviour occurs
for dict ValuesView as well:
py> dict(a).values() == dict(b).values()
False
I think that if a and b are the same Mapping type (say, both dicts, or
both OrderedDicts), then there is an obvious and logical invariant(s).
The following three expressions should be equivalent:
(1) a == b
(2) a.items() == b.items()
(3) (a.keys() == b.keys()) and (a.values() == b.values())
ignoring the usual suspects like NANs and other "funny stuff".
Am I missing something? Is there a rationale for ValuesView to
compare by identity instead of value?
It's not just equality that behaves strangely with ValuesView. Even when
the values are unique and hash-like, they don't behave very "set-like":
# KeysView and ItemsView are set-like
py> a.keys() & b.keys()
{'b', 'a'}
py> a.items() | b.items()
{('b', 2), ('a', 1)}
# values are hashable, but ValuesViews are not set-like
py> set(a.values()) | set(b.values())
{1, 2}
py> a.values() | b.values()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for |: 'ValuesView' and
'ValuesView'
This is *especially* weird when one realises that ItemsView actually
manages to be set-like even when the values are not hashable:
py> c = odict(x=[])
py> c.items() & {}
set()
yet ValuesView isn't set-like when they are!
--
Steve
More information about the Python-ideas
mailing list