ExtensionClass/Persistent and __cmp__ is tricky

Christian Reis kiko at async.com.br
Sun Jun 29 04:24:48 CEST 2003

On Sat, Jun 28, 2003 at 09:36:27PM -0400, Tim Peters wrote:
> >     >>> class Foo(Persistent):
> >     ...    def __cmp__(self, other):
> >     ...     print "Hi there"
> >     ...     return cmp(self, other)
> >     ...
> This doesn't make much sense:  it's defining __cmp__ (indirectly) in terms
> of __cmp__, so it's a recursive mess.

You're right; time for the paper bag.

> >     >>> f = Foo()
> >     >>> f < 1
> It also doesn't make much sense to compare a Foo against an integer.

Maybe not, but it does work for `normal' instances. Should I raise a
TypeError instead in my __cmp__() definition?

I'm unsure of the `correct' semantics here, more than anything.

> >     Hi there [ repeated 21 times ]
> Don't you also see 0 at the end here?
> >     >>> f > 1
> >     Hi there [ repeated 21 times ]
> And don't you also see 0 at the end here?

Yes, these are fine, though the 21 calls had me a bit confused.

> >     >>> 1 < f
> >     0
> >     >>> 1 > f
> >     1

These are the ones I wanted to point out -- their results don't agree
with the values above: f < 1 and 1 < f can't be false simultaneously
unless f == 1 :-)

But my real gripe, actually, was that these didn't call __cmp__(). Now
that I've spent a few more hours on it, I see that Foo types are being
coerced into integers, and that's related to the other `problem' I
reported today.

> > Am I understanding this correctly?
> I don't know -- you haven't said what your understanding is <wink>.

It's not very deep, you've noticed. But I've worried enough over the
matter to understand things a bit further (I had ignored the recursive
call to __cmp__, though; I thought I would have gotten a RuntimeError
there, but I guess not).

> > It seems you can't compare ExtensionClass with basic types; in Python
> > 2.1.3 at least it appears to me that try_3way_compare doesn't want to
> > call tp_compare on the second instance because it's not a PyInstance.
> Possibly so.  I don't think anyone really understands the details of
> ExtensionClass except for Jim (Fulton), and his understanding was fresh
> years ago -- ExtensionClass isn't part of Python, it's part of Zope.

Yes, but it's a fundamental part of the ZODB, which is what I'm
interested in.

> > PS: The interesting part is that it seems that comparing lists *does*
> > work:
> It remains unclear what "work" means to you -- honest!  I can't guess
> what you *expect* any of these things to do.  I don't expect anything
> other than that, e.g., 1<f deliver the same result as f>1.  It

Precisely! And that is *not* true for the integers above! :-) 

I expected consistency when comparing with basic types; sorry if I
wasn't clear enough. However, if the correct policy is to raise a
TypeError, that's fine (and simpler) with me. 

(Unless, of course, we have a coercion problem 8)

> doesn't, so I suppose there's a bug there.  I don't also assume that
> it's worth trying to fix ExtensionClass, though (bang for the buck --
> low (if any) benefit, probably high cost).

One benefit is that it makes things we take for granted with `real'
instances work as expected, which saves us time fussing over details
when trying to get the bigger picture. Because:

> >     >>> [] > f
> >     Hi there [ repeated 21 times ]
> >     0
> >
> > Which means I'm almost safe with using PersistentList, at any rate
> > (which uses its List comparison).

Why am I bothering about this: as I could see it, PersistentList does
cmp() based on its `data' list member. I assumed that comparisons
between lists would be done based on cmp()s on what they contained. To
be safe, as per your suggestion, I reckoned __cmp__() should be
consistent when comparing with other types, and that's where this all
started. It's showing to be a bit embarassing but highly enlightening
(as all newbie things are).

Thanks for the explanation on NESTING_LIMIT. I've already gone back to
the task at hand, but I'm still a bit unhappy because I don't know what
a `carefully written' __cmp__() should do.

Take care,
Christian Reis, Senior Engineer, Async Open Source, Brazil.
http://async.com.br/~kiko/ | [+55 16] 261 2331 | NMFL

More information about the Python-list mailing list