Reputation: 1020
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
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
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
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
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
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