[Python-Dev] PEP 372 -- Adding an ordered directory to collectionsready for pronouncement

Guido van Rossum guido at python.org
Mon Mar 2 20:46:26 CET 2009


On Mon, Mar 2, 2009 at 11:20 AM, Raymond Hettinger <python at rcn.com> wrote:
>> But you'll have to convince me,
>
> Okay, here's one stab at it.  If it doesn't take, I give in.
> ISTM, either way is right depending on your point of view and what
> you're trying do at the time.  My judgment tips in favor of not
> specializing the __eq__ method.

Comparing dicts is relatively uncommon. So we'd have to find and look
at use cases to decide.

> But it is not lost on me why
> one might think that something that iterates in a specified order
> would also make an order sensitive comparison.

My hunch is that not taking the ordering into account is going to
confuse people who consciously use odicts and bother to compare them.
I expect this is going to be a FAQ, no matter how much you try to
document it -- especially since the concept of an odict is so simple
and the API so clean that most people will not bother reading *any*
docs. I expect this to be the most common use case.

Use cases where people compare mappings knowing they may have
different concrete types are probably exceedingly rare, and if I was
doing that I wouldn't rely on __eq__ not being overridden -- IOW I'd
either explicitly invoke Mapping.__eq__(a, b) or write the equivalent
code myself.

The third class of use case is people comparing dicts not thinking
much about the possibility of there being a subclass that overrides
__eq__, and being surprised by the substitution of an odict. This
seems to be the use case you favor; to me it seems pretty rare too. To
convince me otherwise you'd have to find a common use case that does
this *and* is likely to encounter an odict in real life.

>> Liskov cares about the signature, not about the computed value.
>
> That wasn't my understanding.  I thought it was entirely about computed
> values, "Let q(x) be a property provable about objects x of type T. Then
> q(y) should be true for objects y of type S where S is a subtype of T."  Or
> phrased differently, "In class hierarchies, it should be possible to treat a
> specialized object as if it were a base class object."

This strict interpretation is violated all the time in OO programming;
consider e.g. the common overriding of object.__repr__. (In fact, even
the definition of dict.__eq__ overriding object.__eq__ would validate
it.) AFAIK a more common use of the term in OO languages is about
signatures only: if a method of class C accepts an argument of type T,
then you shouldn't override that method in a class D derived from C to
require an argument type S which is a subtype of T. (This is also
known as Contravariance. Read the section on Design by contract in
http://en.wikipedia.org/wiki/Liskov_substitution_principle.)

> In this case, Armin wants to be able to pass in an ordered dictionary to
> functions that weren't designed with ordered dicts in mind (config parser,
> json/yaml parsers, nose, unittest, etc.).  Those functions should be able to
> assume that all the usual dictionary properties are still true.  In
> particular, those functions may make internal comparisons to a regular dict
> (perhaps as a cached value) and would expect those comparisons to succeed.

That's a hypothetical use case. Have you found any real code that uses
__eq__ on dicts in this matter?

>> I would propose the following formal specification for odict.__eq__:
>>
>>  def __eq__(self, other):
>>      if not isinstance(other, odict):
>>          return NotImplemented  # Give other a chance; defaults to False
>>      return list(self.items()) == list(other.items())
>
>
> If I haven't convinced you, then I would be happy to put this in.

Great.

>>> Outside of your differing judgment on the __eq__ method, are you
>>> basically happy with the ordered dict PEP?
>
>> I am.
>
> Once you've decided on __eq__, can I mark the PEP as approved?

Yes. (With the caveat that I haven't read it very closely, but the
basic spec seems sound apart from the __eq__ issue.)

Hm, I wonder if you should spec odict.__repr__ (and hence
odict.__str__). It would be confusing if an odict's repr() were the
same as a plain dict's.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)


More information about the Python-Dev mailing list