Python dictionaries do not have to have restrictions on how data structures are implemented in other languages.
The constraints for an object to be used as a key for a dictionary are: the object must implement a __hash__
method that returns a single constant value; the object has equality comparison with other objects ( __eq__
) - and that neither hash nor equality condition varies while the object is a dictionary key. In general, for simplicity we say that immutable objects can be dictionary keys - but following such constraints even mutable objects can serve.
What "usefulness" varies enormously: it depends on what you want to do - tuples are usually practical because they let you use a dictionary as a sparse array, of course - just use the "get" method to get values:
W = H = 10
a = {}
a[5,5] = 1
print ("\n".join(", ".join(str(a.get((x,y), 0)) for x in range(W)) for y in range(H)) )
In this example, I use the index in the get
method because it allows you to specify a default value for when the key does not exist - (which happens for all combinations of x and y, minus the (5.5) that I declare ). The output is:
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 1, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
Tuples are exceptionally practical because the surrounding parentheses can be omitted when used in an unambiguous context - such as indices within brackets (see example above).
But objects that represent date and time, with rich comparisons, frozen sets, even functions can be used as dictionary keys (in log applications, for example, that count the number of times a function is called, or that they cache) - it's cool not to have an artificial restriction.
A context in which different keys should be taken care of is in applications that have to serialize the data as JSON, such as rest APIs, or calls to some non-relational databases: the JSON standard requires that the chavves are strings.