In-Depth Dive into Python Dictionaries and Sets

Mathematiger
2 min readOct 24, 2024

--

This article handles specialities of the most common Python data structures.

Dictionaries

While normal dictionaries dict are the wide standard of dictionaries, they suffer some difficulties:

  • They don’t save the order of elements added to the dict
  • They don’t have default values of you access elements not in the dictionary
  • Searching for a key in several dictionaries
  • making key-value pairs read-only

This is obviously important in some special cases. Luckily, there are some workarounds.

Order Preservation

This isn’t an issue since Python 3.7. If you work with older Python versions, you can use collections.OrderedDict :

from collections import OrderedDict

ordered_dict = OrderedDict()
ordered_dict[‘a’] = 1
ordered_dict[‘b’] = 2
print(ordered_dict) # Preserves insertion order

Default Values for Missing Pairs

One way is to use the setdefault method for normal Python dict , which only assigns a new value, if the key isn’t present yet.

But in Order for directly manipulating an element, which isn’t present yet, it is easier to set the default elements of a dictionary:

from collections import defaultdict

class RandomClass():
def __init__(self):
pass
def __str__(self):
return f"Random Object with {self.__dict__} as attributes"

default_dict = defaultdict(int) # Default value of 0 for missing keys
print(default_dict['missing_key']) # Outputs 0

# -------------------------------

default_dict = defaultdict(RandomClass) # Default value is the class RandomClass
print(default_dict['missing_key']) # Outputs Random Object with {} as attributes

#---------------------------------
my_dict = defaultdict(list)

# Automatically assigns an empty list if 'a' doesn't exist
my_dict['a'].append(1)
print(my_dict) # {'a': [1]}

This leads to cleaner code, than manually checking if an element exists via my_dict.setdefault('a', []).append(1) .

Searching for a key across multiple dictionaries

If you don’t want to loop over multiple dictionaries, which is time-consuming and not so nice to read, then you can shorten this by using collections.ChainMap :

from collections import ChainMap

dict1 = {'a': 1}
dict2 = {'b': 2}

chain = ChainMap(dict1, dict2)
print(chain['b']) # Searches through all dictionaries

Making key-value pairs read-only

This is done again with another library, collections.MappingProxyType :

from types import MappingProxyType

my_dict = {'a': 1, 'b': 2}
read_only_dict = MappingProxyType(my_dict)

print(read_only_dict['a']) # Works
read_only_dict['a'] = 3 # Raises TypeError: 'mappingproxy' object does not support item assignment

Sets

A Python set is a set of arbitrary hash-able elements. It also suffers from some difficulties:

  • Sometimes it can be important that a set is non-changeable. Hence, these static sets are hashable and can be used as dictionary keys.
  • Sometimes it is important to know, how often an element is in a set. This isn’t possible (or wanted) in normal sets.

Immutability: Frozen sets

# Example of using frozenset
immutable_set = frozenset([1, 2, 3, 4])
print(immutable_set)

# Try modifying it (will raise an error)
immutable_set.add(5) # This will raise an AttributeError

Counting element frequency: collections.Counter

from collections import Counter

# Example of using Counter
elements = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
frequency_counter = Counter(elements)

print(frequency_counter) # Output: Counter({4: 4, 3: 3, 2: 2, 1: 1})
print(frequency_counter[2]) # Frequency of element '2' -> Output: 2

--

--