What you are trying to do is not possible with dictionaries. In fact, it is contrary to the whole idea behind dictionaries.

Also, your Sets class won't help you, as it effectively gives each name a new (sort of random) hash code, making it difficult to retrieve items from the dictionary, other than checking all the items, which defeats the purpose of the dict. You can not do dict.get(Sets(some_name)), as this will create a new Sets object, having a different hash code than the one already in the dictionary!

What you can do instead is:

  1. Just create a list of (name, value) pairs, or

    pairs = zip(names, values) # or list(zip(...)) in Python 3
    
  2. create a dictionary mapping names to lists of values.

    dictionary = {}
    for n, v in zip(names, values):
        dictionary.setdefault(n, []).append(v)
    

The first approach, using lists of tuples, will have linear lookup time (you basically have to check all the entries), but the second one, a dict mapping to lists, is as close as you can get to "multi-key-dicts" and should serve your purposes well. To access the values per key, do this:

for key, values in dictionary.iteritems():
    for value in values:
        print key, value
Answer from tobias_k on Stack Overflow
Top answer
1 of 2
5

What you are trying to do is not possible with dictionaries. In fact, it is contrary to the whole idea behind dictionaries.

Also, your Sets class won't help you, as it effectively gives each name a new (sort of random) hash code, making it difficult to retrieve items from the dictionary, other than checking all the items, which defeats the purpose of the dict. You can not do dict.get(Sets(some_name)), as this will create a new Sets object, having a different hash code than the one already in the dictionary!

What you can do instead is:

  1. Just create a list of (name, value) pairs, or

    pairs = zip(names, values) # or list(zip(...)) in Python 3
    
  2. create a dictionary mapping names to lists of values.

    dictionary = {}
    for n, v in zip(names, values):
        dictionary.setdefault(n, []).append(v)
    

The first approach, using lists of tuples, will have linear lookup time (you basically have to check all the entries), but the second one, a dict mapping to lists, is as close as you can get to "multi-key-dicts" and should serve your purposes well. To access the values per key, do this:

for key, values in dictionary.iteritems():
    for value in values:
        print key, value
2 of 2
2

Instead of wanting multiple keys with the same name, could you getting away of having multiple values per each key?

names = [1]
values = [[1, 2, 3], [4, 5, 6]]

dict = {}

for i in names:
    dict[i] = values

for k,v in dict.items():
    for v in dict[k]:
        print("key: {} :: v: {}".format(k, v))

Output:

key: 1 :: v: [1, 2, 3]
key: 1 :: v: [4, 5, 6]

Then you would access each value like this (or in a loop):

print("Key 1 value 1: {}".format(dict[1][0]))
print("Key 1 value 2: {}".format(dict[1][1]))
Discussions

dictionary - Keys with same name with multiple Values in python - Stack Overflow
One way is to put the value in the list for "Randy", as in dictionary we can't have multiple keys of same name. More on stackoverflow.com
🌐 stackoverflow.com
July 27, 2018
list - Python Dictionary with multiple keys with same name problem - Stack Overflow
From my understanding, a dictionary ... of the same name. This was evident when the output would overwrite itself when it encountered a duplicate value. I tried playing around with a defaultdict but had no luck. My next thought process was to convert it to a list and then to a dictionary using a list as the key but I'm not ... More on stackoverflow.com
🌐 stackoverflow.com
python - A dictionary that allows multiple keys for one value - Code Review Stack Exchange
I'm trying to learn to program on my own with the help of books and the Internet and thought I'd start a project (a sub-project for a project). I want to build a dictionary that allows multiple ke... More on codereview.stackexchange.com
🌐 codereview.stackexchange.com
April 4, 2015
in python, can there be multiple keys of the same name within one dictionary? if so, how would you delete a specific one? - Stack Overflow
in python, can there be multiple keys of the same name within one dictionary? if so, how would you delete a specific one? More on stackoverflow.com
🌐 stackoverflow.com
Top answer
1 of 6
46

I guess you mean this:

class Value:
    def __init__(self, v=None):
        self.v = v

v1 = Value(1)
v2 = Value(2)

d = {'a': v1, 'b': v1, 'c': v2, 'd': v2}
d['a'].v += 1

d['b'].v == 2 # True
  • Python's strings and numbers are immutable objects,
  • So, if you want d['a'] and d['b'] to point to the same value that "updates" as it changes, make the value refer to a mutable object (user-defined class like above, or a dict, list, set).
  • Then, when you modify the object at d['a'], d['b'] changes at same time because they both point to same object.
2 of 6
22

If you're going to be adding to this dictionary frequently you'd want to take a class based approach, something similar to @Latty's answer in this SO question 2d-dictionary-with-many-keys-that-will-return-the-same-value.

However, if you have a static dictionary, and you need only access values by multiple keys then you could just go the very simple route of using two dictionaries. One to store the alias key association and one to store your actual data:

alias = {
    'a': 'id1',
    'b': 'id1',
    'c': 'id2',
    'd': 'id2'
}

dictionary = {
    'id1': 1,
    'id2': 2
}

dictionary[alias['a']]

If you need to add to the dictionary you could write a function like this for using both dictionaries:

def add(key, id, value=None)
    if id in dictionary:
        if key in alias:
            # Do nothing
            pass
        else:
            alias[key] = id
    else:
        dictionary[id] = value
        alias[key] = id

add('e', 'id2')
add('f', 'id3', 3)

While this works, I think ultimately if you want to do something like this writing your own data structure is probably the way to go, though it could use a similar structure.

🌐
Medium
medium.com › internet-of-technology › creating-a-python-dictionary-with-multiple-keys-5bdc50d8adc7
Python: Dictionary with Multiple Keys | Internet of Technology
August 13, 2024 - How can we design a Python dictionary to handle this? ... We will create a custom dictionary class, AgeGroupDict, capable of accepting either an integer representing the patient's age or a string specifying their age group. Here's the implementation: class AgeGroupDict(dict): def __getitem__(self, key): if isinstance(key, int): if key <= 1: age_group = 'Neonate' elif key <= 7: age_group = 'Pediatric' elif key > 7: age_group = 'Adult' else: raise KeyError("Age must be positive.") return super().__getitem__(age_group) elif isinstance(key, str): return super().__getitem__(key) else: raise KeyError("Invalid input.
🌐
Python Guides
pythonguides.com › python-dictionary-multiple-keys
How To Select Multiple Keys From A Dictionary In Python?
March 18, 2025 - One of the best methods for selecting multiple keys from a dictionary is by using the Dictionary comprehension approach. customer = { 'name': 'John Smith', 'age': 35, 'city': 'New York', 'occupation': 'Software Engineer', 'membership': 'Premium'} def select_keys_with_comprehension(original_dict, ...
🌐
EyeHunts
tutorial.eyehunts.com › home › python dictionary same key multiple values | example code
Python dictionary same key multiple values | Example code
October 17, 2023 - Just associate the list object to a key if you want the same key to have multiple values in the Python dictionary. A list object will have multiple elements. ... Simple example code where multiple values in a list correspond to the key so that ...
Find elsewhere
🌐
GeeksforGeeks
geeksforgeeks.org › python › python-initialize-dictionary-with-multiple-keys
Python | Initialize dictionary with multiple keys - GeeksforGeeks
July 12, 2025 - Auxiliary space: O(n), where n is the number of keys in the test_keys list. ... This function is used to actually perform both tasks of multiple assignments and declarations with a single statement. We also use * operator to pack the values together into a dictionary. ... # Python3 code to demonstrate working of # Initialize dictionary with multiple keys # Using fromkeys() # Initialize keys test_keys = ['gfg', 'is', 'best'] # Using fromkeys() # Initialize dictionary with multiple keys res = {**dict.fromkeys(test_keys, 4)} # printing result print("Dictionary after Initializing multiple key-value : " + str(res))
Top answer
1 of 1
10

I want to build a dictionary that allows multiple keys for one value:

This is a very basic relational database.

So the first piece of feedback is that new programmers often start coding with poorly defined test-cases or non-normalised test-cases whereby they get lost developing their test portfolio. If you would have started with clarifying your case, I'm sure you would have cracked this problem.

Let's start defining our operations from examples

Sometimes we will have the database maintaining links:

  • from 1 key to 1 value
  • from 1 key to N values
  • from N keys to 1 value
  • from N keys to N values

A dictionary can hold 1 key to N values, but not N keys to 1 value.

Fortunately the reverse operation of N keys to 1 value is the reverse of the dictionary, so we can trick around this by creating a class:

class Database(object):
    """ A dictionary that allows multiple keys for one value """

    def __init__(self):
        self.keys = {}
        self.values = {}

Next we need figure out how to get data into the database. This is similar to the SQL INSERT STATEMENT, where we maintain both our keys and values in single transactions:

def __setitem__(self, key, value):

Lets first insert a new key, whilst keeping in mind that the value might already exist:

    if key not in self.keys:  
        if value not in self.values:  # it's a new value
            self.keys[key] = set()  # a new set
            self.keys[key].add(value)
            self.values[value] = set()  # a new set
            self.values[value].add(key)
        elif value in self.values:
            self.keys[key] = set()  # a new set
            self.keys[key].add(value)
            self.values[value].add(key) # (1)

(1) a new key to a known value only means an update to the values.

Next we worry about if it's a new relationship with a new value:

    elif key in self.keys:  # 
        self.keys[key].add(value)
        if value not in self.values:
            self.values[value] = set()
            self.values[value].add(key)
        elif value in self.values:
            self.values[value].add(key)

We have now implemented the INSERT STATEMENT in our database.

Now it's time to worry about how to delete records and relationships. For this we hack the __delitem__ function to both take a key and a value. Why? Because otherwise we won't know whether the user wants to delete a single relationship only, OR all entries associated with the key

I thereby choose that:

  • if the value is None I delete every relationship associated with the key.
    • if the value is a valid relationship between the key and value, then I only delete that specific relationship.

This is how it works:

def __delitem__(self, key, value=None): 
    if value is None:
        # All the keys relations are to be deleted.
        try:
            value_set = self.keys[key]
            for value in value_set:
                self.values[value].remove(key)
                if not self.values[value]:
                    del self.values[value]
            del self.keys[key]  # then we delete the key.
        except KeyError:
            raise KeyError("key not found")
    else:  # then only a single relationships is being removed.
        try:
            if value in self.keys[key]:  # this is a set.
                self.keys[key].remove(value)
                self.values[value].remove(key)
            if not self.keys[key]:  # if the set is empty, we remove the key
                del self.keys[key]
            if not self.values[value]:  # if the set is empty, we remove the value
                del self.values[value]
        except KeyError:
            raise KeyError("key not found")

Now we can add and delete. But how about bulk updates? They constitute a special case because __setitem__ can't see that you want to propagate your update onto multiple values. So we need to tell it WHAT to update. Here is a proposal that uses the relationship between the key, the old value and the new value that should be accessible to all keys that other would have a relationship with the old value:

def update(self, key, old_value, new_value):
    if old_value in self.keys[key]:
        affected_keys = self.values[old_value]
        for key in affected_keys:
            self.__setitem__(key, new_value)
            self.keys[key].remove(old_value)
        del self.values[old_value]
    else:
        raise KeyError("key: {} does not have value: {}".format(key,old_value))

So far so good. A slightly annoying thing is that we can't really read what is in the database even though we can get things in and delete them. This calls for the SELECT STATEMENT - or python's __getitem__ method. But(!) we need to be careful, as our database stores data internally as a sets that are accessible from keys. So we need to unpack them onto something useful. As I like working with lists, I have chosen to provide lists, unless its a single value, whereby I only return the value itself:

def __getitem__(self, item):
    values = self.keys[item]
    if len(values) > 1:
        return sorted(list(values))
    elif len(values) == 1:
        return list(values)[0]

Now we just miss one thing to pass all your test: The bulk loading method where you map N keys to M values. This is a "cartesian" product, which is a fancy word all N's maps to all M's. In Python this is a walk in the park as we can iterate over both and reuse our __setitem__ method:

def iterload(self, key_list, value_list):
    for key in key_list:
        for value in value_list:
            self.__setitem__(key, value)

At this point we have implemented:

  • A class for our database
  • A "select" method that is compatible with python d[key]
  • An "insert" method that is compatible with python d[key] = value
  • An "update" method that maintains the relationship to multiple keys.
  • A "delete" method that can both delete a relationship and all entries associated with a key.

Testing

Now I need to test this.

First we load a single key:value pair, where the key is a hashable structure. I chose a tuple with 3 integers:

def test01()
    # hashable key - a tuple
    d = Database()
    k, v = (1, 2, 3), 'magic'
    d[k] = v
    print(d)
    print(d[k])

That works fine as we can see our database object and the value

    # print(d)
    <__main__.Database object at 0x7fd9c3d17048>

    # print(d[k])
    magic

Next we can test our bulk-load method: iterload together with the "many keys - shared value" which is focal in your problem:

def test02():
    # non-hashable key - a list - becomes a many-key shared value
    d = Database()
    keys, value = [1, 2, 3], ['magic']
    d.iterload(keys, value)
    assert d[1] == d[2] == d[3]

This also works as our assertion in the last line doesn't complain: The value of d[1]...d[3] are the same: The text string magic

I add two more tests, which should look very familiar to you, though with minor exceptions:

def test03():
    d = Database()
    k, v = ['what', 'ever'], ['test']
    d.iterload(k,v)
    assert d['what'] == d['ever']
    d['what'] = 'testing'
    try:
        assert d['what'] == d['ever']
    except AssertionError:
        assert True

In test03 I need to pack the value into a list, because iterload needs two iterables. I could made my code much harder to read by accounting for many different cases, but I think the programmer should build a function for one thing and make it clear for future recall of what the function is supposed to do.

In test04 - below - I have added the usage of the update function.

def test04():
    d = Database()
    v = 'test'
    keys, values = ['what', 'ever'], [v]
    d.iterload(keys, values)
    d['whatever'] = 'test'
    assert v == d['whatever']
    assert v == d['what']
    assert d['whatever'] == d['what']
    d.update('whatever', 'test', 'new test')
    a, b = d['whatever'], d['what']
    assert a == b

Everything Together

Here you go:

__author__ = 'root-11'


class Database(object):
    """ A dictionary that allows multiple keys for one value """

    def __init__(self):
        self.keys = {}
        self.values = {}

    def __getitem__(self, item):  # <---SQL SELECT statement
        values = self.keys[item]
        if len(values) > 1:
            return sorted(list(values))
        elif len(values) == 1:
            return list(values)[0]

    def __setitem__(self, key, value):
        if key not in self.keys:  # it's a new key <---SQL INSERT statement
            if value not in self.values:  # it's a new value
                self.keys[key] = set()  # a new set
                self.keys[key].add(value)
                self.values[value] = set()  # a new set
                self.values[value].add(key)
            elif value in self.values:
                self.keys[key] = set()  # a new set
                self.keys[key].add(value) # a new key
                self.values[value].add(key)  # but just an update to the values
        elif key in self.keys:  # it's a new relationships
            self.keys[key].add(value)
            if value not in self.values:
                self.values[value] = set()
                self.values[value].add(key)
            elif value in self.values:
                self.values[value].add(key)

    def update(self, key, old_value, new_value):
        """update is a special case because __setitem__ can't see that
        you want to propagate your update onto multiple values. """
        if old_value in self.keys[key]:
            affected_keys = self.values[old_value]
            for key in affected_keys:
                self.__setitem__(key, new_value)
                self.keys[key].remove(old_value)
            del self.values[old_value]
        else:
            raise KeyError("key: {} does not have value: {}".format(key,old_value))

    def __delitem__(self, key, value=None):  # <---SQL DELETE statement
        if value is None:
            # All the keys relations are to be deleted.
            try:
                value_set = self.keys[key]
                for value in value_set:
                    self.values[value].remove(key)
                    if not self.values[value]:
                        del self.values[value]
                del self.keys[key]  # then we delete the key.
            except KeyError:
                raise KeyError("key not found")
        else:  # then only a single relationships is being removed.
            try:
                if value in self.keys[key]:  # this is a set.
                    self.keys[key].remove(value)
                    self.values[value].remove(key)
                if not self.keys[key]:  # if the set is empty, we remove the key
                    del self.keys[key]
                if not self.values[value]:  # if the set is empty, we remove the value
                    del self.values[value]
            except KeyError:
                raise KeyError("key not found")

    def iterload(self, key_list, value_list):
        for key in key_list:
            for value in value_list:
                self.__setitem__(key, value)

def test01():
    # hashable key - a tuple
    d = Database()
    k, v = (1, 2, 3), 'magic'
    d[k] = v
    print(d)
    print(d[k])


def test02():
    # non-hashable key - a list - becomes a many-key shared value
    d = Database()
    keys, value = [1, 2, 3], ['magic']
    d.iterload(keys, value)
    assert d[1] == d[2] == d[3]


def test03():
    d = Database()
    k, v = ['what', 'ever'], ['test']
    d.iterload(k,v)
    assert d['what'] == d['ever']
    d['what'] = 'testing'
    try:
        assert d['what'] == d['ever']
    except AssertionError:
        assert True


def test04():
    d = Database()
    v = 'test'
    keys, values = ['what', 'ever'], [v]
    d.iterload(keys, values)
    d['whatever'] = 'test'
    assert v == d['whatever']
    assert v == d['what']
    assert d['whatever'] == d['what']
    d.update('whatever', 'test', 'new test')
    a, b = d['whatever'], d['what']
    assert a == b


def do_all():
    for k, v in sorted(globals().items()):
        if k.startswith("test") and callable(v):
            v()

if __name__ == "__main__":
    do_all()
🌐
Google Sites
sites.google.com › site › python3tutorial › data-structures › dictionary › multiple-keys
Python by Examples - Multiple keys
Multi-key combinations to access values a) Table/matrix representation using tupels Tupels are 'hashable' objects and hence can be used as a key in python dictionaries. {(key_part_1, key_part_2):
🌐
Stack Overflow
stackoverflow.com › questions › 50917519 › python-dictionary-keys-with-same-names-are-treated-as-one-entry
Python - Dictionary key's with same names are treated as one entry - Stack Overflow
A python dictionary cannot have duplicate keys, period - the reason is that a python dictionary is a hash table. If you have two destination names as keys that have different travel-time values, it sounds like you have two different destinations, ...
🌐
Codecademy Forums
discuss.codecademy.com › frequently asked questions › python faq
Can a dictionary have two keys of the same value? - Python FAQ - Codecademy Forums
August 4, 2018 - Question Can a dictionary have two keys with the same value? Answer No, each key in a dictionary should be unique. You can’t have two keys with the same value. Attempting to use the same key again will just overwrite the previous value stored.
Top answer
1 of 6
18

For consistency, you should have the dictionary map keys to lists (or sets) of values, of which some can be empty. There is a nice idiom for this:

from collections import defaultdict
d = defaultdict(set)

d["key"].add(...)

(A defaultdict is like a normal dictionary, but if a key is missing it will call the argument you passed in when you instantiated it and use the result as the default value. So this will automatically create an empty set of values if you ask for a key which isn't already present.)


If you need the object to look more like a dictionary (i.e. to set a value by d["key"] = ...) you can do the following. But this is probably a bad idea, because it goes against the normal Python syntax, and is likely to come back and bite you later. Especially if someone else has to maintain your code.

class Multidict(defaultdict):
    def __init__(self):
        super(Multidict, self).__init__(set)

    def __setitem__(self, key, value):
        if isinstance(value, (self.default_factory)): # self.default_factory is `set`
            super().__setitem__(key, value)
        else:
            self[key].append(value)

I haven't tested this.

2 of 6
11

You can also try paste.util.multidict.MultiDict

$ easy_install Paste

Then:

from paste.util.multidict import MultiDict
d = MultiDict()
d.add('a', 1)
d.add('a', 2)
d.add('b', 3)
d.mixed()
>>> {'a': [1, 2], 'b': 3}
d.getall('a')
>>> [1, 2]
d.getall('b')
>>> [3]

Web frameworks like Pylons are using this library to handle HTTP query string/post data, which can have same-name keys.

🌐
GeeksforGeeks
geeksforgeeks.org › python › how-to-add-duplicate-keys-in-dictionary-python
How to Add Duplicate Keys in Dictionary - Python - GeeksforGeeks
July 23, 2025 - Below are some common approaches. Instead of overwriting the value associated with a key, we can associate each key with a list. Whenever a new value needs to be added for the key, we append it to the list.
🌐
PyPI
pypi.org › project › multi_key_dict
multi_key_dict
JavaScript is disabled in your browser. Please enable JavaScript to proceed · A required part of this site couldn’t load. This may be due to a browser extension, network issues, or browser settings. Please check your connection, disable any ad blockers, or try using a different browser
🌐
Medium
medium.com › @matthewghannoum › how-to-build-a-two-or-more-key-dictionary-in-python-9cffe0914b94
How to Build a Multi-Key Dictionary in Python | by Matthew Ghannoum | Medium
February 5, 2024 - To do this I’ve provided code snippets for two custom dictionary classes: ... 🗒️ As mentioned previously, a key is defined as two more values in a tuple or list. The order of those values in the list does not matter. For example, ("a", "b") is equivalent to ("b", "a"). ... get_value_by_key → returns the value stored for a given two key combination, but if there is no value for that combination it returns None. set_key_value_pair → stores a new value or updates an existing one, for a given two key combination.