Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a Python Dictionary as a Key (Non-nested)

People also ask

Can I use a dictionary as a key in Python?

A dictionary or a list cannot be a key. Values, on the other hand, can literally be anything and they can be used more than once.

How do you flatten nested dictionary?

Basically the same way you would flatten a nested list, you just have to do the extra work for iterating the dict by key/value, creating new keys for your new dictionary and creating the dictionary at final step.

Can an empty string be a key in a dictionary Python?

You can't use an empty string. The format strictly limits keys to valid Python identifiers, which means they have to have at least 1 letter or underscore at the start. So the field_name is either an integer or a valid Python identifier.

Can Python dictionary be nested?

In Python, a Nested dictionary can be created by placing the comma-separated dictionaries enclosed within braces.


If you have a really immutable dictionary (although it isn't clear to me why you don't just use a list of pairs: e.g. [('content-type', 'text/plain'), ('host', 'example.com')]), then you may convert your dict into:

  1. A tuple of pairs. You've already done that in your question. A tuple is required instead of list because the results rely on the ordering and the immutability of the elements.

    >>> tuple(sorted(a.items()))
    
  2. A frozen set. It is a more suitable approach from the mathematical point of view, as it requires only the equality relation on the elements of your immutable dict, while the first approach requires the ordering relation besides equality.

    >>> frozenset(a.items())
    

If I needed to use dictionaries as keys, I would flatten the dictionary into a tuple of tuples.

You might find this SO question useful: What is the best way to implement nested dictionaries?

And here is an example of a flatten module that will flatten dictionaries: http://yawpycrypto.sourceforge.net/html/public/Flatten.Flatten-module.html

I don't fully understand your use case and I suspect that you are trying to prematurely optimize something that doesn't need optimization.


To turn a someDictionary into a key, do this

key = tuple(sorted(someDictionary .items())

You can easily reverse this with dict( key )


One way to do this would be to subclass the dict and provide a hash method. ie:

class HashableDict(dict):
    def __hash__(self):
        return hash(tuple(sorted(self.iteritems())))

>>> d = HashableDict(a=1, b=2)
>>> d2 = { d : "foo"}
>>> d2[HashableDict(a=1, b=2)]
"foo"

However, bear in mind the reasons why dicts (or any mutable types) don't do this: mutating the object after it has been added to a hashtable will change the hash, which means the dict will now have it in the wrong bucket, and so incorrect results will be returned.

If you go this route, either be very sure that dicts will never change after they have been put in the other dictionary, or actively prevent them (eg. check that the hash never changes after the first call to __hash__, and throw an exception if not.)


Hmm, isn't your use case just memoizing function calls? Using a decorator, you will have easy support for arbitrary functions. And yes, they often pickle the arguments, and using circular reasoning, this works for non-standard types as long as they can be pickled.

See e.g. this memoization sample


I'll sum up the options and add one of my own, you can :

  • make a subclass to dict and provide a hash function
  • flatten the dict into a tuple
  • pickle the dict
  • convert the Dict into a string using the json module (as shown below)
import json
Dict = {'key' :'value123'}
stringifiedDict = json.dumps(Dict)
print(stringifiedDict)
# {"key": "value123"}
newDict = {stringifiedDict: 12345}
print(newDict[stringifiedDict])
# 12345
for key, val in newDict.items():
    print(json.loads(key))
    # {'key': 'value123'}
    print(json.loads(key)['key'])
    # value123