[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