Title: PEP 372 odict.__eq__ behaves incorrectly
Type: behavior Stage:
Components: None Versions: Python 2.5
Status: closed Resolution: works for me
Dependencies: Superseder:
Assigned To: rhettinger Nosy List: cegner, rhettinger
Priority: normal Keywords:

Created on 2009-08-19 22:29 by cegner, last changed 2009-08-20 01:25 by rhettinger. This issue is now closed.

Messages (4)
msg91752 - (view) Author: Christopher Egner (cegner) Date: 2009-08-19 22:29
The current definition for odict.__eq__ is
    def __eq__(self, other):
        if isinstance(other, OrderedDict):
            return all(p==q for p, q in  _zip_longest(self.items(),
        return dict.__eq__(self, other)

The current behavior of NotImplemented is:
>>> if( NotImplemented ):
...     print 'foo'
>>> dict.__eq__( {}, None )
>>> if ( dict.__eq__( {}, None ) ):
...     print 'oops'

The surprising behavior is:
>>> if ( OrderedDict() != None ):
...     print 'okie'
... else:
...     print 'gah!'

As best I understand it, normally other (in this case None) would be
given the chance to evaluate other.__eq__( OrderedDict() ), but this
doesn't seem to be happening.
msg91754 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2009-08-19 23:15
I cannot reproduce your final example:

Python 2.7a0 (trunk, Aug  4 2009, 12:07:15)
>>> from collections import OrderedDict
[41375 refs]
>>> if (OrderedDict() != None):
...     print 'okie'
... else:
...     print 'gah'

Both are based on OrderedDict.__eq__ defined as:

    def __eq__(self, other):
        '''od.__eq__(y) <==> od==y.  Comparison to another OD is
        while comparison to a regular mapping is order-insensitive.

        if isinstance(other, OrderedDict):
            return len(self)==len(other) and \
                   all(p==q for p, q in zip(self.items(), other.items()))
        return dict.__eq__(self, other)

Other questions about your bug report.  
* When you refer to odict, do you mean OrderedDict()?
* Do you understand that NotImplemented only does its magic
  in the context of the == or != operator, and it bypassed
  which you write dict.__eq__ or OrderedDict.__eq__?
* Are you clear that bool(NotImplemented) always evaluates to True?

Python 3.1.1 (r311:74483, Aug 17 2009, 17:02:12) [MSC v.1500 32 bit
(Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> from collections import OrderedDict
>>> if (OrderedDict() != None):
...	print('Okie')
... else:
...	print('Gah')

msg91755 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2009-08-19 23:19
If you need an implementation for OrderedDict that runs on Pythons
before 2.7 or 3.1, use the recipe at:

That code matches what was actually added to the language.
msg91756 - (view) Author: Christopher Egner (cegner) Date: 2009-08-19 23:53
I was running the file from the PEP, figured out that things
were going off the rails at dict.__eq__ and generalised, saw the same
implementation in OrderedDict, I thought the same problem would exist. 
This is what I get for taking a shortcut.

I checked out the activestate recipe mentioned in msg91755 which works.

The version, here is a literal paste from the pdb prompt (aside
from changing some of the more private data to xxx):
(Pdb) p urlConsolidationArtefact_row_prev
odict.odict([(u'id', 58768L), (u'urlConsolidationRun_id', 22L),
(u'valid', True), (u'validated', False), (u'refererUrl',
u''), (u'refererUrl_hash',
'\xa60\xe2\xb8D\x7fv\x03\xb1=\xf3{\x15\xc0\xb0)'), (u'url',
u'http://xxx'), (u'url_hash',
(u'updatedAt', datetime.datetime(2009, 8, 15, 10, 54, 15)),
(u'createdAt', datetime.datetime(2009, 8, 15, 10, 54, 14))])
(Pdb) p urlConsolidationArtefact_row_prev != None
(Pdb) p urlConsolidationArtefact_row_prev == None

So there is a problem at least in the odict module provided by (referenced in the
PEP, once more prominently than now, I think).

Anyhow, I don't really know the details of what python does with
NotImplemented but version you gave doesn't have the same problem, so
I'll gladly use that instead.

If you can confirm that there's no deeper issue here, I'll be glad to
close the bug.

Thanks for the help!
Date User Action Args
2009-08-20 01:25:20rhettingersetstatus: open -> closed
resolution: works for me
2009-08-19 23:53:30cegnersetmessages: + msg91756
versions: - Python 2.6, Python 3.0, Python 3.1, Python 2.7, Python 3.2
2009-08-19 23:19:56rhettingersetmessages: + msg91755
2009-08-19 23:15:27rhettingersetmessages: + msg91754
2009-08-19 22:52:24rhettingersetassignee: rhettinger

nosy: + rhettinger
2009-08-19 22:29:13cegnercreate