1

If we have 2 separate dict, both with the same keys and values, when we print them it will come in different orders, as expected.
So, let's say I want to to use hash() on those dict:

hash(frozenset(dict1.items()))
hash(frozenset(dict2.items()))

I'm doing this to make a new dict with the hash() value created as the new keys .
Even showing up different when printing dict, the value createad by hash() will always be equal? If no, how to make it always the same so I can make comparisons successfully?

5
  • So, consider key1 from the 1st line and key2 from the 2nd. If I make if (key1 == key1) will always be true? Just making sure, sorry bout my lack of experience. Commented Jan 5, 2016 at 6:24
  • 2
    Why would they come in different orders? There's no randomness in hashing or dictionary insertion right? Commented Jan 5, 2016 at 6:25
  • Well, dicts don't have a specified order right? I'm wondering if this can change the hash value Commented Jan 5, 2016 at 6:31
  • @JayanthKoushik: Order can change for dicts with the same keys if there are hash collisions, and the history of the dicts differs. If you insert two objects with the same hash (after cut down to match number of buckets) into a dict (or set/frozenset), a and b, and in a different collection, insert b then a, then the relative ordering of those two items will differ. And it's even more complex if values are deleted, not just added, thanks to dummy placeholders used to ensure chained values aren't lost. Simple example in my answer. Commented Jan 5, 2016 at 6:56
  • @AdrianoFerrariCardoso: It can't. As noted in my answer, frozenset and hashable guarantees ensure that the hash is consistent, even though ordering might differ depending on how the frozenset is constructed. Commented Jan 5, 2016 at 6:58

1 Answer 1

4

If the keys and values hash the same, frozenset is designed to be a stable and unique representation of the underlying values. The docs explicitly state:

Two sets are equal if and only if every element of each set is contained in the other (each is a subset of the other).

And the rules for hashable types require that:

Hashable objects which compare equal must have the same hash value.

So by definition frozensets with equal, hashable elements are equal and hash to the same value. This can only be violated if a user-defined class which does not obey the rules for hashing and equality is contained in the resulting frozenset (but then you've got bigger problems).

Note that this does not mean they'll iterate in the same order or produce the same repr; thanks to chaining on hash collisions, two frozensets constructed from the same elements in a different order need not iterate in the same order. But they're still equal to one another, and hash the same (precise outputs and ordering is implementation dependent, could easily vary between different versions of Python; this just happens to work on my Py 3.5 install to create the desired "different iteration order" behavior):

>>> frozenset([1,9])
frozenset({1, 9})
>>> frozenset([9,1])
frozenset({9, 1}) # <-- Different order; consequence of 8 buckets colliding for 1 and 9
>>> hash(frozenset([1,9]))
-7625378979602737914
>>> hash(frozenset([9,1]))
-7625378979602737914 # <-- Still the same hash though
>>> frozenset([1,9]) == frozenset([9,1])
True # <-- And still equal
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.