booleans, hash() and objects having the same value

Ryszard Szopa ryszard.szopa at gmail.com
Wed Jan 30 20:14:32 EST 2008


Hi all,

I've just read PEP 285 so I understand why bool inherits from int and
why, for example,  ((False - True)*True)**False==1. This was necessary
for backwards compatibility and to give the beast some ability to do
moral reasoning. For example, Python knows to value the whole truth
more than just a half-truth:

In [95]: True > 0.5*True
Out[95]: True

Anyway, the thing that bothers me is the behavior of booleans when
passed as argument to the hash() function... That is, hash(True) ==
hash(1) and hash(False) == hash(0). This leads to a rather
counterintuitive interaction with dicts:

In [124]: d = {}

In [125]: d[True] = repr(True)

In [126]: d[1] = repr(1)

In [127]: d[True]
Out[127]: '1'

In [128]: d
Out[128]: {True: '1'}

You may argue that this is a rather strange use case... However, you
may imagine that somebody would want a dict mapping from objects to
their representations, with 0, 1 and booleans among the objects, like
in:

In [123]: dict((el, repr(el)) for el in [0, 1, True, False])
Out[123]: {0: 'False', 1: 'True'}

In both cases, the result is rather unexpected, though after some
thinking, understandable (`==' tests the equality of values of
objects, True==1, and (from the documentation of hash) "Two objects
with the same value have the same hash value"). However, is this
approach really sound? Wouldn't it be more sensible to have bool its
own __hash__?

PEP 285 doesn't mention anything about hashing (in fact, it doesn't
contain the string `hash' at all). Is it that nobody has noticed the
problem, it is a well known fact usually classified as a non-problem,
or maybe there are some serious reasons to keep 1 and True having the
same hash value?

(Also, it is not completely clear what it means for two Python objects
to "have the same value". My first intuition would be that variables
may have a value, which usually is some Python object. The second
intuition would be that objects with compatible (i.e. one inherits
from the other) types and ==-equal dicts have the same value. However,
this is _sometimes_ true. On one hand:

In [173]: True == 1
Out[173]: True

In [165]: class MyDict(dict): pass
   .....:

In [175]: x = {'a': 1}

In [176]: w = MyDict(a=1)

In [177]: w == x
Out[177]: True

But, on the other hand:

In [178]: class Foo(object): pass
   .....:

In [179]: class Bar(Foo): pass
   .....:

In [180]: foo = Foo()

In [181]: bar = Bar()

In [182]: bar.__dict__==foo.__dict__
Out[182]: True

In [183]: bar == foo
Out[183]: False

*Truly* puzzling, I must say.)

Best regards,

    -- Richard



More information about the Python-list mailing list