[Python-Dev] Getting values stored inside sets

Paul Moore p.f.moore at gmail.com
Fri Apr 3 18:57:29 CEST 2009


2009/4/3 Steven D'Aprano <steve at pearwood.info>:
> Python does not promise that if x == y, you can use y anywhere you can
> use x. Nor should it. Paul's declaration of abuse of __eq__ is
> unfounded.

Sorry, I was trying to simplify what I was saying, and simplified it
to the point where it didn't make sense :-) Martin (quoted below)
explained what I was trying to say far more clearly.

2009/4/3 "Martin v. Löwis" <martin at v.loewis.de>:
> If you have a set of elements, and you check "'foo' in s", then
> you should be able just to use the string 'foo' itself for whatever
> you want to do with it - you have essentially created a set of
> strings. If you think that 'foo' and Element('foo') are different
> things, you should not implement __eq__ in a way that they are
> considered equal.

-- in particular, if you're using things in sets (which are *all
about* equality, insofar as that's how "duplicates" are defined) you
should ensure that your definition of __eq__ respects the idea that
equal objects are duplicates (ie, interchangeable). Otherwise, a dict
is the appropriate data structure.

Actually, given the definition in the original post,

class Element(object):
   def __init__(self, key):
       self.key = key
   def __eq__(self, other):
       return self.key == other
   def __hash__(self):
       return hash(self.key)

as far as I can tell, equality is *only* defined between Elements and
keys - not even between 2 elements! So with that definition, there
could be many Elements in a set, all equal to the same key. Which is
completely insane.

In fact, Python seems to be doing something I don't understand:

>>> class Element(object):
...    def __init__(self, key, id):
...        self.key = key
...        self.id = id
...    def __eq__(self, other):
...        print "Calling __eq__ for %s" % self.id
...        return self.key == other
...    def __hash__(self):
...        return hash(self.key)
...
>>> a = Element('k', 'a')
>>> b = Element('k', 'b')
>>> a == b
Calling __eq__ for a
Calling __eq__ for b
True
>>> a == a
Calling __eq__ for a
Calling __eq__ for a
True
>>>

Why does __eq__ get called twice in these cases? Why does a == b, as
that means a.key == b, and clearly a.key ('k') does *not* equal b. Or
are there some further options being tried, in str,__eq__ or
object.__eq__? The documentation doesn't say so... Specifically,
there's nothing saying that a "reversed" version is tried.

Paul.


More information about the Python-Dev mailing list