[Python-ideas] Fwd: Why do equality tests between OrderedDict keys/values views behave not as expected?

Andrew Barnert abarnert at yahoo.com
Thu Dec 17 11:57:21 EST 2015


On Dec 17, 2015, at 03:19, Franklin? Lee <leewangzhong+python at gmail.com> wrote:
> 
> So the issues are:

I think the first issue is that, if the comparison behavior of dict views isn't documented anywhere, it probably should be. (Even if the intended rule is just "comparisons may not be meaningful or do different things in different implementations, don't use them for anything", that could be documented.)

As it stands, you can guess:

* since all mapping keys and items act like sets (and are Sets), they probably compare like sets
* since there is no OrderedSet for OrderedDict's keys and values to act like, they probably don't compare like those and instead just compare like sets
* since values are just generic collections, they probably just use generic identity comparison.

But, even if that guess may happen to be right for all builtin and stdlib types, and all user types that rely on the ABCs as mixins, in all of the major implementations, it's still just a guess, not something I'd want to rely on in portable code. 

> 1. OrderedDict().values() does not implement __eq__. It uses object
> equality, which means identity.
> 1a. dict().values() does not implement __eq__.
> 
> 2. OrderedDict().keys().__eq__ does not respect order.
> 
> I'd argue that keys() should be ordered comparisons, and values()
> could be.

So what happens when you compare the keys, items, or values view from an OrderedDict against the view from another mapping type? Or, for keys and items, against another set type? If you leave that up to the whichever one is on the left, you get cases where a==b and b!=a. If you leave it up to the most derived type (by the usual __rspam__-like rules), that doesn't help anything, since dict_keys_view and odict_keys_view are unrelated except in sharing an abstract base class. And, worst of all, even if you contrive a way for one or the other to always win consistently, you get cases where a==b and b==c and a!=c.

Also, overriding equality for ordered dict views might make sense, but what about ordering? I think it's pretty reasonable to expect that something that acts like a set and inherits from Set use < to mean subset, not lexicographical comparison. But then the interactions with other mapping views get even crazier.

Under the current rules, I'm pretty sure equality is always symmetric and transitive, ordering is consistent with the normal partial order rules, etc. New rules that seem more intuitive at first glance but break down as soon as you try to think them through don't seem like an improvement.

Finally, why should these comparisons be sequence-like? Yes, OrderedDict and its views do have a defined order, but they still don't act like sequences in other ways. You can't subscript or slice them, they follow dict rather than sequence rules for modifying during iteration (although I believe those rules aren't enforced in the code so you get arbitrary exceptions or wrong values instead of the RuntimeError from dict?), they fail isinstance(x, Sequence), etc. What other non-sequence types implement sequence comparisons?

Maybe what you really want is new methods to get sequence-like (but with O(1) __contains__ and friends) rather than set-like views, including implementing the Sequence ABC, which only exist on OrderedDict, compare like sequences, don't provide set operations or implement Set, etc. Then you can be explicit about which one you want. The question is, are you going to actually want the sequence-like views often enough for it to be worth adding all of that code?

> As a plus, this could be more efficient than unordered
> comparisons, since it's just
>    return all(x == y for x, y in zip(self.keys(), other.keys()))
> instead of packing each into a set and comparing the sets.

I think you want zip_longest(self.keys(), other.keys(), fill=object()) or equivalent; otherwise {1, 2} will be equal to {1, 2, 3} .

Also, you don't need to pack self.keys() into a set; it already is a Set, and implements all of the immutable set operations as-is, without needing any conversions.

But really, who cares which of two implementations is more efficient when they implement two completely different things? If set comparison is right, it doesn't matter that sequence comparison is faster, you still can't use it, and vice-versa.

> But what
> would be the point of comparing values views?
> 
> On the other hand, I guess dict().values().__eq__ should stay
> unimplemented. What would it mean? MultiSet comparison? Values in
> general aren't even hashable, so they can't be stuck into a hash-based
> set structure. Maybe explicitly make it NotImplemented.
> 
> 
> On Thu, Dec 17, 2015 at 4:40 AM, Alexandre Figura
> <ipipomme+python at gmail.com> wrote:
>> 
>> Hi,
>> 
>> I recently compared OrderedDict instances while writing unit tests, and
>> discovered an interesting behavior. If I create two ordered dictionaries
>> with the same keys/values in the same order, I observe that their values are
>> not equal when I compare them.
>> 
>> I recently asked a question about this on Stackoverflow:
>> http://stackoverflow.com/questions/34312674/why-values-of-an-ordereddict-are-not-equal
>> 
>> Moreover, another user observed that keys of ordered dictionaries are
>> compared in an order insensitive way:
>> http://stackoverflow.com/questions/34320600/why-does-the-ordereddict-keys-view-compare-order-insensitive
>> 
>> Are there any reasons for such implementation choices? As it appears
>> disturbing for many people, would it be possible to update these behaviors?
>> 
>> Best Regards,
>> Alexandre.
>> 
>> 
>> _______________________________________________
>> Python-ideas mailing list
>> Python-ideas at python.org
>> https://mail.python.org/mailman/listinfo/python-ideas
>> Code of Conduct: http://python.org/psf/codeofconduct/
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/


More information about the Python-ideas mailing list