== Exploring a surprise with equality in Python Taken from [[@hackedy's tweet https://twitter.com/hackedy/status/486576539274711040]], here's an interesting Python surprise: .pn prewrap on > >>> {1: "one", True: "two"} > {1: 'two'} > >>> {0: "one", False: "two"} > {0: 'two'} There are two things happening here to create this surprise. The starting point is this: > >>> print hash(1), hash(True) > 1 1 At one level, Python has made _True_ have the same [[hash value UnderstandingHashing]] as _1_. Actually that's not quite right, so let me show you the real story: > >>> isinstance(True, int) > True Python has literally made _bool_, the type that _True_ and _False_ are instances of, be a subclass of _int_. They not merely look like numbers, they *are* numbers. As numbers their [[hash identity UnderstandingHashing]] is their literal value of _1_ or _0_, and of course they also compare equal to literal _1_ or _0_. Since they hash to the same identity and compare equal, we run into [[the issue with 'custom' equalities and hashes in dictionaries TwoEqualitiesAndHash]] where Python considers the two different objects to be the same key and everything gets confusing. (That _True_ and _False_ hash to the same thing as _1_ and _0_ is probably not a deliberate choice. The internal _bool_ type doesn't have a custom hash function; it just tacitly inherits the hash function of its parent, ie _int_. I believe that Python could change this if it wanted to, which would make the surprise here go away.) The other thing is what happens when you create a dictionary with literal syntax, which is that Python generates bytecode that stores each initial value into the dictionary one after another in the order that you wrote them. It turns out that when you do a redundant store into a dictionary (ie you store something for a key that already exists), Python only replaces the value, not both the key and the value. This is why the result is not '_{True: 'two'}_'; only the value got overwritten in the second store. (This decision is a sensible one because it may avoid object churn and the overhead associated with it. If Python replaced the key as well it would at least be changing more reference counts on the key objects. And under normal circumstances you're never going to notice the difference unless you're going out of your way to look.) PS: It turns out that [[@hackedy beat me to discovering that bools are ints https://twitter.com/hackedy/status/486581030380257282]]. Also the class documentation for _bool_ says this explicitly (and notes that _bool_ is one of the rare Python classes that can't be subclassed).