Fabian
Fabian

Reputation: 1020

Python: how does a dict with mixed key type work?

I understand that the following is valid in Python: foo = {'a': 0, 1: 2, some_obj: 'c'}

However, I wonder how the internal works. Does it treat everything (object, string, number, etc.) as object? Does it type check to determine how to compute the hash code given a key?

Upvotes: 9

Views: 20689

Answers (5)

Pete Cacioppi
Pete Cacioppi

Reputation: 920

It might be easier to ignore dictionaries for a moment, and just think of sets. You can probably see how a set s might consist of {'a', 1, some_object}, right? And that if you tried to add 1 to this set, it wouldn't do anything (since 1 is already there)?

Now, suppose you try to add a another_object to s. another_object is not 1 or 'a', so to see if it can be added to s, Python will see if another_object is equal to some_object. Understanding object equality is a whole nother subject, but suffice it to say, there is a sensible way to go about it. If another_object == some_object is true, then s will remain unchanged. Otherwise, s will consist of {'a', 1, some_object, another_object}.

Hopefully, this makes sense to you. If it does, then just think of dictionaries as special sets. The keys of the dictionary are the entries of the set, and values of the dictionary just hold a single value for each key. Saying d['and now'] = 'completely different' is just the same thing as deleting 'and now' from the set, and then adding it back it again with 'completely different' as its associated value. (This isn't technically how a dict handles __setitem__ , but it can be helpful to think of a dict as working this way. In reality, sets are more like crippled dicts than dicts are like extra powerful sets).

Of course, with dicts you should bear in mind that only hashable objects are allowed in a dict. But that is itself a different subject, and not really the crux of your question, AFAICT

Upvotes: 0

tripleee
tripleee

Reputation: 189507

Everything in Python is an object, and every object which has a __hash__ method can be used as a dictionary key. How exactly the method (tries to) return a unique integer for each possible key is thus specific to each class, and somewhat private (to use the term carelessly for humorous effect). See https://wiki.python.org/moin/DictionaryKeys for details.

(There are a couple of other methods your class needs to support before it is completely hashable. Again, see the linked exposition.)

Upvotes: 1

Martin Konecny
Martin Konecny

Reputation: 59631

You can answer this by opening a Python interactive prompt and trying several of these keys:

>>> hash('a')
12416037344
>>> hash(2)
2
>>> hash(object())
8736272801544

Does it treat everything (object, string, number, etc.) as object?

You are simply using the hash function to represent each dictionary key as an integer. This integer is simply used to index in the underlying dictionary array. Assuming a dictionary starts of with a pre-allocated size of 8, we use the modulus operator (the remainder) to fit it into an appropriate location:

>>> hash('a')
12416037344
>>> hash(object()) % 8
2

So in this particular case, the hashed object is placed in index 2 of the underlying array. Of course there can be collisions, and so depending on the underlying implementation, the underlying array may actually be an array of arrays.

Note that items that aren't hashable cannot be used as dictionary keys:

>>> hash({})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'

Proof:

>>> d = {}
>>> d[{}] = 5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'

Upvotes: 3

gabhijit
gabhijit

Reputation: 3585

I think it would work as long, the object supports __hash__ method and the __hash__(self) of two objects return same values for which __eq__ returns True. hashable objects are explained here.

eg. Try following

a = []
a.__hash__ == None # True
aa = 'xyz'
aa.__hash__ == None # False
a = (1,1,) # A Tuple, hashable
a.__hash__ == None # False

Hope that helps

Upvotes: 0

jwilner
jwilner

Reputation: 6606

Types aren't used the same way in Python as statically types languages. A hashable object is simply one with a valid hash method. The interpreter simply calls that method, no type checking or anything. From there on out, standard hash map principles apply: for an object to fulfill the contract, it must implement both hash and equals methods.

Upvotes: 12

Related Questions