In Python, a dictionary is a collection of key-value pairs. Each key-value pair maps the key to its associated value. Dictionaries are defined with curly braces {} with keys and values separated by a colon :. The elements are separated by commas. Here's how you can initialize a dictionary:
myDict = {'name': 'Alice', 'age': 25} # A dictionary with string keys and mixed type values
emptyDict = {} # An empty dictionary
You can access the value associated with a specific key using the square bracket [] syntax. Modifying a dictionary value is done by assigning a new value to a key.
print(myDict['name']) # Accessing the value of the key 'name'
myDict['age'] = 30 # Changing the value associated with the key 'age'
If you try to access a key that does not exist in the dictionary, Python will raise a KeyError.
Adding a new key-value pair is straightforward:
myDict['address'] = '123 Elm Street' # Adds a new key-value pair
To remove a key-value pair, you can use the pop() method or the del keyword:
myDict.pop('address') # Removes the key 'address' and returns its value
del myDict['age'] # Removes the key 'age' without returning its value
You can iterate over the keys, values, or key-value pairs in a dictionary:
# Iterating over keys
for key in myDict:
print(key)
# Iterating over values
for value in myDict.values():
print(value)
# Iterating over key-value pairs
for key, value in myDict.items():
print(key, value)
Use the in keyword to check if a key is in a dictionary:
if 'name' in myDict:
print("Name is a key in the dictionary")
Python provides various methods that you can use with dictionaries:
myDict.keys() # Returns a view object containing the keys of the dictionary
myDict.values() # Returns a view object containing the values of the dictionary
myDict.items() # Returns a view object containing key-value pairs as tuples
myDict.get('age', 0) # Returns the value for 'age' if it exists, else returns 0
myDict.update({'age': 35, 'gender': 'Female'}) # Updates the dictionary with the provided key-value pairs
myDict.clear() # Removes all items from the dictionary
setdefault(key[, default]) # Returns the value of a specified key. If the key does not exist, it inserts the key with the specified default value.
Just like lists, dictionaries can also be nested. This means a dictionary can contain another dictionary as a value.
nestedDict = {
'dict1': {'key1': 1, 'key2': 2},
'dict2': {'key3': 3, 'key4': 4}
}
Here's an example of declaring, initializing, and using a dictionary in Python:
employee = {
'name': 'John Doe',
'role': 'Software Developer',
'age': 28
}
for key, value in employee.items():
print(f"{key}: {value}")
- Keys in a dictionary must be unique and immutable. This means you cannot use lists or dictionaries as keys.
- From Python 3.7 onwards, dictionaries maintain insertion order by default.
- Accessing a nonexistent key will raise a KeyError. It's often safer to use the get() method.
- Memory usage can be higher in dictionaries compared to lists due to the storage of keys and values.
- Performance: Dictionary operations like accessing, adding, and removing elements are generally O(1), making them very efficient.
The update() method modifies a dictionary in-place by adding key-value pairs from another dictionary. If a key already exists, its value is updated.
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}
dict1.update(dict2) # dict1 is now {'a': 1, 'b': 3, 'c': 4}
When you directly assign one dictionary to another or use the update() method, any changes made to the values of the original dictionary will reflect in the other if the values are mutable objects.
original = {'a': [1, 2], 'b': 3}
copy = original
copy['a'].append(3) # Modifies the list in 'original' as well
# original is now {'a': [1, 2, 3], 'b': 3}
In Python 3.5+, you can use the ** unpacking operator to merge dictionaries. This creates a new dictionary without modifying the originals.
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}
merged_dict = {**dict1, **dict2} # {'a': 1, 'b': 3, 'c': 4}
When merging dictionaries using methods like the ** operator, dictionary comprehension, or using methods like dict(), the original dictionaries remain independent. Changes to one won't affect the other, unless the values themselves are mutable objects (like lists or other dictionaries).
dict1 = {'a': [1, 2]}
dict2 = {'b': 3}
merged = {**dict1, **dict2}
merged['a'].append(3)
# dict1 is now {'a': [1, 2, 3]} because the list is a mutable object
# dict2 remains {'b': 3}
You can manually loop through one dictionary and add its key-value pairs to another. This is more verbose and less efficient but works in all versions of Python.
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}
for key, value in dict2.items():
dict1[key] = value # dict1 is now {'a': 1, 'b': 3, 'c': 4}
ChainMap from the collections module can be used to group multiple dictionaries and treat them as a single mapping. It doesn't create a new dictionary but a view that shows the merged result.
from collections import ChainMap
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}
merged = ChainMap(dict1, dict2) # Not a new dict, but a view of dict1 and dict2
You can also use a dictionary comprehension to merge dictionaries, which is a more Pythonic and elegant way.
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}
merged_dict = { k: v
for d in [dict1, dict2]
for k, v in d.items()
}
To completely isolate dictionaries, especially when they contain mutable objects, you can use a deep copy. This creates new instances of the mutable objects, ensuring that changes in one dictionary do not affect the other.
import copy
original = {'a': [1, 2], 'b': 3}
deep_copy = copy.deepcopy(original)
deep_copy['a'].append(3)
# original remains {'a': [1, 2], 'b': 3}
In Python, there isn't a built-in immutable dictionary type equivalent to IReadOnlyDict in C#. However, there are several ways to create a read-only or immutable-like dictionary:
The MappingProxyType from the types module creates a read-only view of the original dictionary. It doesn't allow any modification but reflects any changes made to the underlying dictionary.
from types import MappingProxyType
original_dict = {'a': 1, 'b': 2}
read_only_dict = MappingProxyType(original_dict)
# read_only_dict['a'] = 3 # This will raise a TypeError
Another approach is to subclass dict and override the methods that modify the dictionary.
class ImmutableDict(dict):
def __setitem__(self, key, value):
raise TypeError("Cannot modify ImmutableDict")
def __delitem__(self, key):
raise TypeError("Cannot modify ImmutableDict")
# Usage
immutable_dict = ImmutableDict(a=1, b=2)
# immutable_dict['a'] = 3 # Raises TypeError
You can create a custom wrapper class that only implements read methods.
class ReadOnlyDict:
def __init__(self, data):
self._data = data
def __getitem__(self, key):
return self._data[key]
def __iter__(self):
return iter(self._data)
def __len__(self):
return len(self._data)
# You can add other dictionary read methods here
# Usage
original_dict = {'a': 1, 'b': 2}
read_only_dict = ReadOnlyDict(original_dict)