[ZODB-Dev] 0 is not really equal to my object

Tim Peters tim at zope.com
Tue Feb 8 16:45:17 EST 2005


[Derrick Hudson]
> The attached script shows the problem I discovered.  Adjust the path
> at the beginning to refer to your zope installation.  The problem only
> exhibits itself when the class inherits from Persistent.

Or derives in any other way from ExtensionClass, an old Zope-specific
feature that doesn't play well with many newer Python features.  You don't
need Zope for this, BTW -- just having a ZODB before 3.3 is enough:

"""
import ZODB
from Persistence import Persistent

class Infinite(Persistent):
    def __cmp__(self, other) :
        print "__cmp__", self, other
        if self is other:
            return 0 # eq
        return 1 # greater than anything else

# singleton
Infinite = Infinite()

# These two yield wrong result
print "1", 0 != Infinite
print "2", 0 == Infinite

# these two work
print
print "3", 1 != Infinite
print "4", 1 == Infinite

# these two work correctly, with or without the __cmp__ method above
print "\n5", Infinite != 0
print "\n4", Infinite == 0

print
print "6", Infinite == Infinite
print "7", Infinite != Infinite
"""

Under ZODB 3.2.5, that produced this output (and it would have helped had
you been this specific about the output you got):

1 False
2 True

3 True
4 False

5 __cmp__ <Infinite instance at 008CD6E0> 0
True

4 __cmp__ <Infinite instance at 008CD6E0> 0
False

6 __cmp__ <Infinite instance at 008CD6E0> <Infinite instance at 008CD6E0>
True
7 __cmp__ <Infinite instance at 008CD6E0> <Infinite instance at 008CD6E0>
False

In ZODB 3.3, Persistent no longer derives from ExtensionClass, and is a
vanilla "new-style" Python class (albeit coded in C) instead.  The import
has to change then, to:

from persistent import Persistent

and the output changes to:

1 __cmp__ <__main__.Infinite object at 0x008CE6F0> 0
True
2 __cmp__ <__main__.Infinite object at 0x008CE6F0> 0
False

3 __cmp__ <__main__.Infinite object at 0x008CE6F0> 1
True
4 __cmp__ <__main__.Infinite object at 0x008CE6F0> 1
False

5 __cmp__ <__main__.Infinite object at 0x008CE6F0> 0
True

4 __cmp__ <__main__.Infinite object at 0x008CE6F0> 0
False

6 __cmp__ <__main__.Infinite object at 0x008CE6F0> <__main__.Infinite object
at 0x008CE6F0>
True
7 __cmp__ <__main__.Infinite object at 0x008CE6F0> <__main__.Infinite object
at 0x008CE6F0>
False

Those are probably what you were expecting.  Rich comparisons (and other
newer Python features) can also be used in ZODB 3.3 with Persistent
subclasses.

> To summarize, if an (in)equality comparison is performed and the int 0
> is on the left-hand side of the comparison, the result is inverted.
>
> I am using zope 2.7.1 with python 2.3.4 on debian linux.  (this is
> part of a Z4I-based project)
>
> Will someone confirm this as a bug or point out something I am doing
> wrong?

Well, *I'd* call it a bug, but at the same time I don't think there's a real
chance it will be fixed before ZODB 3.3 (where it's already fixed).  Mucking
with the ExtensionClass implementation before then is as likely to introduce
as many new bugs as got fixed (it's complicated, deep black-magic C code).

Googling on

     ExtensionClass comparison

turns up a suggested workaround from 2000, but I'm afraid I don't understand
it:

    http://mail.python.org/pipermail/python-dev/2000-October/010117.html

(Best guess is that "make your ExtensionClass a numeric type" is something
that can only be done at the C level; adding methods like __nonzero__() to
your class doesn't make any difference to the results printed by your
program on my box under ZODB 3.2.5)

I think the last time this was discussed on zodb-dev starts here:

    http://mail.zope.org/pipermail/zodb-dev/2003-June/005430.html

I stand by my claim there that nobody can predict when an ExtensionClass's
__cmp__() will get invoked during mixed-type comparisons.  So best advice I
can give is to abandon this approach, and try something else.



More information about the ZODB-Dev mailing list