An unhashable object cannot be inserted into a dict. It is documented, there is good reason for it.
However, I do not understand why it affects a membership test:
if value not in somedict:
print("not present")
I was assuming that a membership test can return only True
or False
. But when the value
is unhashable, it fails with TypeError: unhashable type
. I would say True
should be the correct answer of this not in
test, because the value
is clearly not contained in somedict
and it is fully irrelevant that it cannot be inserted.
Another example:
try:
result = somedict[value]
except KeyError:
# handle the missing key
When the value is unhashable, it fails with TypeError: unhashable type
I would expect the KeyError
instead.
Also:
somedict.get(value, default)
does not return the default, but throws the TypeError
.
So why unhashable in somedict
does not evaluate to False
and what is the correct test returning just True or False?
Update:
object.__contains__(self, item)
Called to implement membership test operators. Should return true if item is in self, false otherwise.
(from "Data Model - Python Documentation")
Appendix:
This is a simplified part of a user interface program, which failed when one of the arguments was a dict.
# args = list of function arguments created from user's input
# where "V1" stands for value1 and "V2" stands for value2
XLAT = {'V1': value1, 'V2': value2}
args = [XLAT.get(a, a) for a in args]
function(*args)
Second, a dictionary key must be of a type that is immutable. For example, you can use an integer, float, string, or Boolean as a dictionary key. However, neither a list nor another dictionary can serve as a dictionary key, because lists and dictionaries are mutable.
Properties of Dictionary KeysThe values in the dictionary can be of any type, while the keys must be immutable like numbers, tuples, or strings. Dictionary keys are case sensitive- Same key name but with the different cases are treated as different keys in Python dictionaries.
Python's dictionaries are kind of hash table type. They work like associative arrays or hashes found in Perl and consist of key-value pairs. A dictionary key can be almost any Python type, but are usually numbers or strings. Values, on the other hand, can be any arbitrary Python object.
Python dictionaries allow us to associate a value to a unique key, and then to quickly access this value. It's a good idea to use them whenever we want to find (lookup for) a certain Python object. We can also use lists for this scope, but they are much slower than dictionaries.
The reason is that the test for a potential key being part of a dictionary is done by generating the hash value of the potential key. If the potential key cannot provide a hash value (if the object is not hashable), the test cannot take place.
You are right, in a way, that in this case the existence test could just say "no, not present" ("because it cannot be inserted anyway").
This is not done this way because it could cloak a lot of programming errors.
If you program cleanly, you will most likely never check for an unhashable object whether it is in a dictionary or not. I. e. it requires quite an amount of fantasy to come up with a case where you actually would. (I wouldn't say it is completely out of the question, though.) The amount of cases where such a check is only happening because a programming error leads to a situation where you do something accidentally, is way larger. So the exception indicates that you should look at the spot in the code.
If you know what you are doing (maybe the case in your situation), you should simply catch that error:
try:
if strange_maybe_unhashable_value in my_dict:
print("Yes, it's in!")
else:
print("No, it's not in!")
except TypeError:
print("No, it's not even hashable!")
If you want to combine that with your KeyError
handling:
try:
result = somedict[value]
except (KeyError, TypeError):
# handle the missing key
or
try:
result = somedict[value]
except KeyError:
# handle the missing key
except TypeError:
# react on the thing being unhashable
To provide another aspect which is rather esoteric:
An object might be hashable at some time and unhashable at another (maybe later). This should of course never be the case but can happen, e. g. if the hash value relies on something external. Despite common assumptions, being hashable is independent from being immutable (although one often relies on the other). So an object could change while being part of a dictionary, and this could change its hash value. While this is an error in itself and will lead to having the dictionary not working properly, this might also be a design-reason not to simply say "not present" or raise a KeyError
but raise the TypeError
instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With