__eq__ on a dict

N

Neil Benn

Hello,

I can't find the docs for __eq__ on a dict and I can't find
a description on what the eq does (strangely it does implement > and <
but I have no idea what that does). Does anyone know (definitively)
what the __eq__, __gt__, __lt__ methods do.

BTW, google is not my friend - I invited it out for a drink last
week and it stood me up :).

Cheers,

Neil

--

Neil Benn
Senior Automation Engineer
Cenix BioScience
BioInnovations Zentrum
Tatzberg 46
D-01307
Dresden
Germany

Tel : +49 (0)351 4173 154
e-mail : (e-mail address removed)
Cenix Website : http://www.cenix-bioscience.com
 
N

Neil Benn

Hmm, can't see anything about implementation of python dict methods
__eq__, __lt__ or __gt__ there - general docs but not specific to the
dict here - at least not as far as I can see from these docs.

Neil

--

Neil Benn
Senior Automation Engineer
Cenix BioScience
BioInnovations Zentrum
Tatzberg 46
D-01307
Dresden
Germany

Tel : +49 (0)351 4173 154
e-mail : (e-mail address removed)
Cenix Website : http://www.cenix-bioscience.com
 
S

Steven D'Aprano

Hello,

I can't find the docs for __eq__ on a dict and I can't find
a description on what the eq does (strangely it does implement > and <
but I have no idea what that does). Does anyone know (definitively)
what the __eq__, __gt__, __lt__ methods do.

BTW, google is not my friend - I invited it out for a drink last
week and it stood me up :).

It works for me. Google on "__eq__ Python" and the 5th and 6th sites are:

http://python.active-venture.com/ref/customization.html
http://www.network-theory.co.uk/docs/pylang/ref_32.html

Normally, asking Python for help is a good way to read the docs, but in
this particular case, it is a big let-down:

py> help({}.__eq__)
Help on method-wrapper:

__eq__ = <method-wrapper object>


For any two objects x and y, when you call

x == y

Python calls x.__eq__(y). That includes dicts:

py> dictA = {0: "spam"}
py> dictB = {0: "sp" + "am"}
py> dictC = {1: "ham"}
py>
py> dictA == dictB
True
py> dictA.__eq__(dictB) # same as dictA == dictB
True
py> dictB == dictC # calls dictB.__eq__(dictC)
False

Two dicts are equal if they have the same keys and the same values.

In general, you should not call __eq__ directly, but use the == operator
instead.

Likewise:

x > y becomes x.__gt__(y)
x < y becomes x.__lt__(y)
x >= y becomes x.__ge__(y)
x <= y becomes x.__le__(y)
x != y becomes x.__ne__(y)
x <> y also becomes x.__ne__(y)
 
A

Aaron Bingham

Steven D'Aprano said:
Hello,

I can't find the docs for __eq__ on a dict and I can't find
a description on what the eq does (strangely it does implement > and <
but I have no idea what that does). Does anyone know (definitively)
what the __eq__, __gt__, __lt__ methods do.
[snip]

For any two objects x and y, when you call

x == y

Python calls x.__eq__(y). That includes dicts:

py> dictA = {0: "spam"}
py> dictB = {0: "sp" + "am"}
py> dictC = {1: "ham"}
py>
py> dictA == dictB
True
py> dictA.__eq__(dictB) # same as dictA == dictB
True
py> dictB == dictC # calls dictB.__eq__(dictC)
False

Two dicts are equal if they have the same keys and the same values.

That is what I would expect, but where is that documented? Also,
where is the behavior of the much less obvious dictionary methods
__ge__, __gt__, __le__, __lt__, and __cmp__ methods documented?
In general, you should not call __eq__ directly, but use the == operator
instead.

That is clear enough, the OP was seeking information about the
behavior of these operators when used with dictionaries.

Thanks,

--
 
N

Neil Benn

Steven said:
Normally, asking Python for help is a good way to read the docs, but in
this particular case, it is a big let-down:

py> help({}.__eq__)
Help on method-wrapper:

__eq__ = <method-wrapper object>


For any two objects x and y, when you call
x == y

<snip>

<snip>
That's the empirical evidence that I got but I want to be 100% sure that
this holds in all cases - I'm wary about using empirical evidence
leading to assumptions in my code - I take the paradigm that 'Assumption
is the mother of all f**k-ups'.
In general, you should not call __eq__ directly, but use the == operator
instead.
<snip>
Yeah I'm aware of that, I didn't want to start talking about ==, etc
or I may mislead people into the - this is what __eq__ means path of
explanation.

Thanks for your response.

Neil

--

Neil Benn
Senior Automation Engineer
Cenix BioScience
BioInnovations Zentrum
Tatzberg 46
D-01307
Dresden
Germany

Tel : +49 (0)351 4173 154
e-mail : (e-mail address removed)
Cenix Website : http://www.cenix-bioscience.com
 
S

Steven D'Aprano

That is what I would expect, but where is that documented? Also,
where is the behavior of the much less obvious dictionary methods
__ge__, __gt__, __le__, __lt__, and __cmp__ methods documented?


That is clear enough, the OP was seeking information about the
behavior of these operators when used with dictionaries.

That wasn't clear from his post at all. If he had explained what he
wanted, I wouldn't have wasted my time explaining what he already knew.

You know, something like "I already know that __eq__ is equivalent to ==,
likewise for the other operators > etc, what I want to know is how are
equality, less than, greater than, etc implemented specifically for dicts."

Asking the right question helps. But not in this case, because comparison
of objects is ... confusing. There doesn't seem to be any definitive
answer to the question, not that I have been able to find, although plenty
of hints.

My first thought was the comparisons between dicts is implemented as
comparisons between their items, ie cmp(dictA, dictB) is turned into
cmp(dictA.items(), dictB.items()). But that doesn't seem to be the case:

py> dictA = {None: None, 1:1}
py> dictB = {1: 1}
py> cmp(dictA, dictB)
1
py> cmp(dictA.items(), dictB.items())
-1

My second thought was that comparison is implemented by first comparing
keys, then values, ie cmp(dictA, dictB) turns into:

order = cmp(dictA.keys(), dictB.keys())
if order == 0: # keys are equal
order = cmp(dictA.values(), dictB.values())
return order

I don't think I can prove it though.
 
S

Steven D'Aprano

Replying to myself... how sad.

That wasn't clear from his post at all. If he had explained what he
wanted, I wouldn't have wasted my time explaining what he already knew.

On reading it, that came across more snarky than I intended. Sorry.
Asking the right question helps. But not in this case, because comparison
of objects is ... confusing. There doesn't seem to be any definitive
answer to the question, not that I have been able to find, although plenty
of hints.

My first thought was the comparisons between dicts is implemented as
comparisons between their items, ie cmp(dictA, dictB) is turned into
cmp(dictA.items(), dictB.items()). But that doesn't seem to be the case:

However, I wasn't completely insane, since I came across this tidbit:

http://python.active-venture.com/ref/comparisons.html

"Mappings (dictionaries) compare equal if and only if their sorted (key,
value) lists compare equal. Outcomes other than equality are resolved
consistently, but are not otherwise defined."

with a footnote leading to this comment:

"Earlier versions of Python used lexicographic comparison of the sorted
(key, value) lists, but this was very expensive for the common case of
comparing for equality."

I also suggested:
My second thought was that comparison is implemented by first comparing
keys, then values, ie cmp(dictA, dictB) [snip]
I don't think I can prove it though.

I certainly can't prove it, since my example pseudo-code fails even on the
example I used earlier. Sigh.

In summary:

Equality of dicts is guaranteed. Two dicts are equal if and only if their
keys:value pairs are equal. Other orderings between dicts are calculated
consistently but not in any documented way.


One gotcha is that some dicts are unordered:

py> {1:1j} < {1:2j}
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: cannot compare complex numbers using <, <=, >, >=

but even that is special-cased up to the wazzoo:

py> {1:1j} < {1:1j}
False
 
A

Aaron Bingham

Hi Steven,

Thanks for digging into this.

Steven D'Aprano said:
Replying to myself... how sad.



On reading it, that came across more snarky than I intended. Sorry.

It's ok. I realize the OP did not make it crystal clear what he was
getting at in his post. It's easier when you are sitting in the same
office ;-).
However, I wasn't completely insane, since I came across this tidbit:

http://python.active-venture.com/ref/comparisons.html

"Mappings (dictionaries) compare equal if and only if their sorted (key,
value) lists compare equal. Outcomes other than equality are resolved
consistently, but are not otherwise defined."

with a footnote leading to this comment:

"Earlier versions of Python used lexicographic comparison of the sorted
(key, value) lists, but this was very expensive for the common case of
comparing for equality."

Ah, I missed that, thanks for the pointer. Seems information of
dictionary comparisons should also appear in the Library Reference
under Mapping Types.
I also suggested:
My second thought was that comparison is implemented by first comparing
keys, then values, ie cmp(dictA, dictB) [snip]
I don't think I can prove it though.

Looking at the source code links Simon posted (thanks Simon!) it is
clear that, in the current version of CPython, dictionaries are
ordered first by length and only if the lengths are equal are the
keys and values examined.
Equality of dicts is guaranteed. Two dicts are equal if and only if their
keys:value pairs are equal. Other orderings between dicts are calculated
consistently but not in any documented way.

One gotcha is that some dicts are unordered:

py> {1:1j} < {1:2j}
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: cannot compare complex numbers using <, <=, >, >=

but even that is special-cased up to the wazzoo:

py> {1:1j} < {1:1j}
False

Hmm... not sure I like that!

--
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

ConfigParser Keys 1
Plone FAQ 1
Python Twain 0
UML Tools 1
How to close a process in win32 0
epyDoc Questions 2
Pyhton Interpreter Startup time 16
CGI, FieldStorage and Filename 0

Members online

No members online now.

Forum statistics

Threads
473,989
Messages
2,570,207
Members
46,782
Latest member
ThomasGex

Latest Threads

Top