key:value
pairs in curly braces.key:value
pairs and want to search a value given the key efficiently.help(dict)
Help on class dict in module builtins: class dict(object) | dict() -> new empty dictionary | dict(mapping) -> new dictionary initialized from a mapping object's | (key, value) pairs | dict(iterable) -> new dictionary initialized as if via: | d = {} | for k, v in iterable: | d[k] = v | dict(**kwargs) -> new dictionary initialized with the name=value pairs | in the keyword argument list. For example: dict(one=1, two=2) | | Built-in subclasses: | StgDict | | Methods defined here: | | __contains__(self, key, /) | True if the dictionary has the specified key, else False. | | __delitem__(self, key, /) | Delete self[key]. | | __eq__(self, value, /) | Return self==value. | | __ge__(self, value, /) | Return self>=value. | | __getattribute__(self, name, /) | Return getattr(self, name). | | __getitem__(...) | x.__getitem__(y) <==> x[y] | | __gt__(self, value, /) | Return self>value. | | __init__(self, /, *args, **kwargs) | Initialize self. See help(type(self)) for accurate signature. | | __iter__(self, /) | Implement iter(self). | | __le__(self, value, /) | Return self<=value. | | __len__(self, /) | Return len(self). | | __lt__(self, value, /) | Return self<value. | | __ne__(self, value, /) | Return self!=value. | | __repr__(self, /) | Return repr(self). | | __reversed__(self, /) | Return a reverse iterator over the dict keys. | | __setitem__(self, key, value, /) | Set self[key] to value. | | __sizeof__(...) | D.__sizeof__() -> size of D in memory, in bytes | | clear(...) | D.clear() -> None. Remove all items from D. | | copy(...) | D.copy() -> a shallow copy of D | | get(self, key, default=None, /) | Return the value for key if key is in the dictionary, else default. | | items(...) | D.items() -> a set-like object providing a view on D's items | | keys(...) | D.keys() -> a set-like object providing a view on D's keys | | pop(...) | D.pop(k[,d]) -> v, remove specified key and return the corresponding value. | If key is not found, d is returned if given, otherwise KeyError is raised | | popitem(self, /) | Remove and return a (key, value) pair as a 2-tuple. | | Pairs are returned in LIFO (last-in, first-out) order. | Raises KeyError if the dict is empty. | | setdefault(self, key, default=None, /) | Insert key with a value of default if key is not in the dictionary. | | Return the value for key if key is in the dictionary, else default. | | update(...) | D.update([E, ]**F) -> None. Update D from dict/iterable E and F. | If E is present and has a .keys() method, then does: for k in E: D[k] = E[k] | If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v | In either case, this is followed by: for k in F: D[k] = F[k] | | values(...) | D.values() -> an object providing a view on D's values | | ---------------------------------------------------------------------- | Class methods defined here: | | fromkeys(iterable, value=None, /) from builtins.type | Create a new dictionary with keys from iterable and values set to value. | | ---------------------------------------------------------------------- | Static methods defined here: | | __new__(*args, **kwargs) from builtins.type | Create and return a new object. See help(type) for accurate signature. | | ---------------------------------------------------------------------- | Data and other attributes defined here: | | __hash__ = None
students = ['rauf', 'arif', 'maaz', 'hadeed', 'mujahid']
marks = [81, 52, 70, 74, 78]
def get_marks(name):
i = students.index(name)
return marks[i]
get_marks('hadeed')
74
get_marks('maaz')
70
key:value
pairs in curly braces.# A dictionary with string keys, and integer values, showing age of person
dict1 = {
'arif':51,
'rauf':52,
'hadeed':22
}
print(dict1)
print(type(dict1))
print(id(dict1))
{'arif': 51, 'rauf': 52, 'hadeed': 22} <class 'dict'> 140419669449344
# A dictionary with integer keys, and string values, showing a symbol table generated by compiler
dict2 = {
2580:'var1',
2582:'var2',
2586:'var3'
}
dict2
{2580: 'var1', 2582: 'var2', 2586: 'var3'}
# dictionary with mixed keys (immutable types only)
dict3 = {
'name': 'kakamanna',
1: 10,
'abc':25,
33: 'xyz'
}
dict3
{'name': 'kakamanna', 1: 10, 'abc': 25, 33: 'xyz'}
# creating dictionary using dict() method
dict4 = dict({1: 'hello', 2: 'bye'})
dict4
{1: 'hello', 2: 'bye'}
# Creating an empty dictionary
dict5 = dict()
dict5
{}
# other way to create empty dictionary
dict6 = {}
dict6
{}
# A list of two object tuples can also be used to create dictionaries
dict7 = dict([('name', 'arif'), ('age',51), ('city', 'Lahore')])
dict7
{'name': 'arif', 'age': 51, 'city': 'Lahore'}
# Duplicate values are allowed
d1 = {'name1' : 'kakamanna',
'name2' : 'kakamanna'
}
d1
{'name1': 'kakamanna', 'name2': 'kakamanna'}
# Duplicate keys are not allowed
# This will not raise an error, but will overwrite the value corresponding to the key
d1 = {'name' : 'kakamanna',
'name' : 'arif'
}
d1
{'name': 'arif'}
# Tuple being immutable can be used as a key
d1 = {'kakamanna':'name',
(60, 78, 83): 'marks'
}
d1
{'kakamanna': 'name', (60, 78, 83): 'marks'}
# List being mutable cannot be used as a key
d1 = {'kakamanna':'name',
[60, 78, 83]:'marks'
}
d1
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) /var/folders/1t/g3ylw8h50cjdqmk5d6jh1qmm0000gn/T/ipykernel_28173/357288203.py in <module> 1 # List being mutable cannot be used as a key ----> 2 d1 = {'kakamanna':'name', 3 [60, 78, 83]:'marks' 4 } 5 d1 TypeError: unhashable type: 'list'
# List being mutable can be used as a value
d1 = {'nam':'kakamanna',
'marks':[60,78,83]
}
d1
{'nam': 'kakamanna', 'marks': [60, 78, 83]}
# Tuple being immutable can also be used as a value
d1 = {'nam':'kakamanna',
'marks': (60,78,83)
}
d1
{'nam': 'kakamanna', 'marks': (60, 78, 83)}
dict3 = {
'name': 'kakamanna',
1: 10,
'abc':25,
33: 'xyz'
}
dict3
{'name': 'kakamanna', 1: 10, 'abc': 25, 33: 'xyz'}
# Creating a Nested Dictionary
dict7 = {'name':'arif',
'occupation':'teaching',
'address':{'house#' : 131, 'area' : 'model town', 'city' : 'lahore'},
'phone': '03214456454'
}
dict7
{'name': 'arif', 'occupation': 'teaching', 'address': {'house#': 131, 'area': 'model town', 'city': 'lahore'}, 'phone': '03214456454'}
d1 = {
'arif':51,
'rauf':52,
'hadeed':20
}
d1
d2 = {
'arif':51,
'rauf':52,
'hadeed':20
}
d2
d3 = {
'rauf':52,
'hadeed':20,
'arif':51
}
id(d1), id(d2), id(d3)
(140419669239424, 140419668292416, 140419668418176)
value
of a Dictionary given a key
¶[]
operatordict.get(key)
methodd1 = {
'name':'kakamanna',
'age':22,
'address':'Johar Town',
'marks':[60, 75, 80]
}
d1['address']
'Johar Town'
d1.get('marks')
[60, 75, 80]
To retrieve a value from a nested dictionary
d2 = {'name':'arif',
'occupation':'teaching',
'address':{'house#' : 131,
'area' : 'model town',
'city' : 'lahore'
}
}
d2
{'name': 'arif', 'occupation': 'teaching', 'address': {'house#': 131, 'area': 'model town', 'city': 'lahore'}}
d2['address']
{'house#': 131, 'area': 'model town', 'city': 'lahore'}
d2['address']['city']
'lahore'
d2.get('address')
{'house#': 131, 'area': 'model town', 'city': 'lahore'}
d2.get('address').get('city')
'lahore'
key:value
pairs from a Dictionary using dict.items()
method¶dict.items()
method returns all the key-value pairs of a dictionary as a two object tupled1 = {
'name':'kakamanna',
'age':22,
'address':'Johar Town',
'marks':[60, 75, 80]
}
l1 = d1.items()
l1
dict_items([('name', 'kakamanna'), ('age', 22), ('address', 'Johar Town'), ('marks', [60, 75, 80])])
keys
of a Dictionary using dict.keys()
method¶dict.keys()
method returns all the keys of a dictionary objectd1 = {
'name':'kakamanna',
'age':22,
'address':'Johar Town',
'marks':[60, 75, 80]
}
d1.keys()
dict_keys(['name', 'age', 'address', 'marks'])
values
from a Dictionary using dict.values()
method¶dict.values()
method returns all the values of a dict objectd1 = {
'name':'kakamanna',
'age':22,
'address':'Johar Town',
'marks':[60, 75, 80]
}
d1.values()
dict_values(['kakamanna', 22, 'Johar Town', [60, 75, 80]])
[]
Operator¶[]
operator and assignment statementdict[key] = value
# Create a simple dictionary
d1 = {
'name':'kakamanna',
'age':22,
'address':'Johar Town',
'marks':[60, 75, 80]
}
d1
{'name': 'kakamanna', 'age': 22, 'address': 'Johar Town', 'marks': [60, 75, 80]}
# Modify value corresponding to an existing key
d1['address'] = 'Model Town'
d1
{'name': 'kakamanna', 'age': 22, 'address': 'Model Town', 'marks': [60, 75, 80]}
# Adding a new key:value pair
d1['key1'] = 'value1'
d1
{'name': 'kakamanna', 'age': 22, 'address': 'Model Town', 'marks': [60, 75, 80], 'key1': 'value1'}
d1.update()
method¶d1.update()
method is used to update the value corresponding to an existing key inside the dictionarydict.update(key:value)
# Create a simple dictionary
d1 = {
'name':'kakamanna',
'age':22,
'address':'Johar Town',
'marks':[60, 75, 80]
}
d1
{'name': 'kakamanna', 'age': 22, 'address': 'Johar Town', 'marks': [60, 75, 80]}
# Modify value corresponding to an existing key
d1.update({'name':'Arif Butt'})
d1
{'name': 'Arif Butt', 'age': 22, 'address': 'Johar Town', 'marks': [60, 75, 80]}
# Adding a new key:value pair
d1.update({'key2':'value2'})
d1
{'name': 'Arif Butt', 'age': 22, 'address': 'Johar Town', 'marks': [60, 75, 80], 'key2': 'value2'}
You can use the dict.update()
method to merge two dictionaries
d1 = {
'name':'kakamanna',
'age':22,
}
d2 = {
'address':'Johar Town',
'marks':[60, 75, 80]
}
d1.update(d2)
d1
{'name': 'kakamanna', 'age': 22, 'address': 'Johar Town', 'marks': [60, 75, 80]}
[]
operator¶del d1[key]
del d1
d1 = {
'name':'kakamanna',
'age':22,
'address':'Johar Town',
'marks':[60, 75, 80]
}
d1
{'name': 'kakamanna', 'age': 22, 'address': 'Johar Town', 'marks': [60, 75, 80]}
del d1['age']
d1
{'name': 'kakamanna', 'address': 'Johar Town', 'marks': [60, 75, 80]}
#this will delete the whole directory
del d1
print(d1) # will generate an error now
--------------------------------------------------------------------------- NameError Traceback (most recent call last) /var/folders/1t/g3ylw8h50cjdqmk5d6jh1qmm0000gn/T/ipykernel_28173/1687696692.py in <module> 1 #this will delete the whole directory 2 del d1 ----> 3 print(d1) # will generate an error now NameError: name 'd1' is not defined
d1.popitem()
Method¶d1.popitem()
removes and returns a (key,value) pair as a 2-tupled1 = {
'name':'kakamanna',
'age':22,
'address':'Johar Town',
'marks':[60, 75, 80]
}
d1
{'name': 'kakamanna', 'age': 22, 'address': 'Johar Town', 'marks': [60, 75, 80]}
d1.popitem()
('marks', [60, 75, 80])
d1.popitem()
('address', 'Johar Town')
d1
{'name': 'kakamanna', 'age': 22}
d1.pop(key)
Method¶d1.pop(key)
returns the value only of the key passed as its required argumentd1 = {
'name':'kakamanna',
'age':22,
'address':'Johar Town',
'marks':[60, 75, 80]
}
d1
{'name': 'kakamanna', 'age': 22, 'address': 'Johar Town', 'marks': [60, 75, 80]}
d1.pop('name')
'kakamanna'
d1
{'age': 22, 'address': 'Johar Town', 'marks': [60, 75, 80]}
#d1.pop('nokey') #This will raise an error
d1.clear()
Method¶d1.clear()
removes all items from the dictionary and returns Noned1 = {
'name':'kakamanna',
'age':22,
'address':'Johar Town',
'marks':[60, 75, 80]
}
d1
{'name': 'kakamanna', 'age': 22, 'address': 'Johar Town', 'marks': [60, 75, 80]}
d1.clear()
d1
{}
# Create a simple dictionary for these operations
d1 = {
'Name': 'Kakamanna',
'Sex': 'Male',
'Age': 23,
'Height': 6.1,
'Occupation': 'Student'
}
d1
{'Name': 'Kakamanna', 'Sex': 'Male', 'Age': 23, 'Height': 6.1, 'Occupation': 'Student'}
# The items() method, returns an object of dict_items containing two value tuples
rv = d1.items()
print(rv)
print("\n", type(rv))
dict_items([('Name', 'Kakamanna'), ('Sex', 'Male'), ('Age', 23), ('Height', 6.1), ('Occupation', 'Student')]) <class 'dict_items'>
# You can convert dictionary key-value pairs into a tuple containing two valued tuples
t1 = tuple(d1.items())
print(t1)
print("\n", type(t1))
(('Name', 'Kakamanna'), ('Sex', 'Male'), ('Age', 23), ('Height', 6.1), ('Occupation', 'Student')) <class 'tuple'>
#converting dictionary keys only into a tuple
t1 = tuple(d1.keys())
print(t1)
print("\n", type(t1))
('Name', 'Sex', 'Age', 'Height', 'Occupation') <class 'tuple'>
#converting dictionary values only into a list
mylist = list(d1.values())
print("\n", mylist)
print(type(mylist))
['Kakamanna', 'Male', 23, 6.1, 'Student'] <class 'list'>
sorted(iterable)
to get a sorted copy of a dictionary (by value).sorted(iterable)
returns a sorted version of the iterable, without making any change to the iterable.list.sort()
method, however, the iterator to be sorted needs to be passed as a required parameteras shown below: sorted(iterable, key=None, reverse=False)
reverse
argument is False
, you override the default behavior by passing a True
value to this argument to perform a descending sortConsider the following dictionary having names
as keys and marks
as values
dict1 = {'rauf': 81,
'arif':90,
'maaz':76,
'hadeed':73,
'mujahid':93,
}
dict1
{'rauf': 81, 'arif': 90, 'maaz': 76, 'hadeed': 73, 'mujahid': 93}
sorted(dict1, reverse=True)
['rauf', 'mujahid', 'maaz', 'hadeed', 'arif']
When you pass a dictionary object to the sorted()
function, it will return the list of sorted dictionary keys
d2 = sorted(dict1)
d2
['arif', 'hadeed', 'maaz', 'mujahid', 'rauf']
You can pass the keys only to the sorted()
function, to do the above task
d2 = sorted(dict1.keys())
d2
['arif', 'hadeed', 'maaz', 'mujahid', 'rauf']
Similarly you can pass the values only to the sorted()
function, and it will return the list of sorted values
d2 = sorted(dict1.values())
d2
[73, 76, 81, 90, 93]
Let us do customized sorting with Python Dictionaries
Example 1: Suppose we have a dictionary containing student names along with their marks and we want to sort the dictionary by highest marks of the students first
dict1 = {'rauf': 81,
'arif':90,
'maaz':76,
'hadeed':73,
'mujahid':93,
}
dict1
{'rauf': 81, 'arif': 90, 'maaz': 76, 'hadeed': 73, 'mujahid': 93}
# Function receives a key:value tuple (key, value) and returns the value
def func1(item):
return item[1]
mylist = sorted(dict1.items(), key = func1, reverse=True)
print(mylist)
[('mujahid', 93), ('arif', 90), ('rauf', 81), ('maaz', 76), ('hadeed', 73)]
Note the sorted()
function returned a list object in which each element is a two valued tuple having (key,value) pairs. You can always typecast such lists to a dictionary object
sorted_dict = dict(mylist)
sorted_dict
{'mujahid': 93, 'arif': 90, 'rauf': 81, 'maaz': 76, 'hadeed': 73}
type(sorted_dict)
dict
Example 2: Suppose we have a JSON array containing name, age and grades of students. We want to sort it by the age of the students.
key:value
pairs# The following JSON array defines a student object with 3 properties: `name`, `age`, and `grade`
# It is actually a list containing dictionary objects each object containing three key:value pairs
students = [
{"name": "Hashim", "age": 18, "grade": "B"},
{"name": "Salman", "age": 11, "grade": "A"},
{"name": "Mazhar", "age": 12, "grade": "C"},
{"name": "Farhan", "age": 22, "grade": "D"},
{"name": "Bilal", "age": 19, "grade": "A"},
{"name": "Zalaid", "age": 17, "grade": "B"}
]
students
[{'name': 'Hashim', 'age': 18, 'grade': 'B'}, {'name': 'Salman', 'age': 11, 'grade': 'A'}, {'name': 'Mazhar', 'age': 12, 'grade': 'C'}, {'name': 'Farhan', 'age': 22, 'grade': 'D'}, {'name': 'Bilal', 'age': 19, 'grade': 'A'}, {'name': 'Zalaid', 'age': 17, 'grade': 'B'}]
# Function receives a dictionary object and returns the value corresponding to key age in that dictionary
def func2(item):
return item.get('age') #return item['age']
sorted_students = sorted(students, key = func2)
sorted_students
[{'name': 'Salman', 'age': 11, 'grade': 'A'}, {'name': 'Mazhar', 'age': 12, 'grade': 'C'}, {'name': 'Zalaid', 'age': 17, 'grade': 'B'}, {'name': 'Hashim', 'age': 18, 'grade': 'B'}, {'name': 'Bilal', 'age': 19, 'grade': 'A'}, {'name': 'Farhan', 'age': 22, 'grade': 'D'}]
Note the sorted()
function returned a list object in which each element is a dictionary object having three key:value pairs
=
Operator¶=
operator to create a copy/alias of an object.dict1 = {'rauf': 81,
'arif':90,
'maaz':76,
'hadeed':73,
'mujahid':93,
}
dict2 = dict1
# Both references point to same memory object, so have the same ID
print('ID of dict1:', id(dict1))
print('ID of dict2:', id(dict2))
ID of dict1: 140419669413952 ID of dict2: 140419669413952
# If you modify an element of one object, the change will be visible in both
dict2["maaz"] = 100
print('\ndict1:', dict1)
print('dict2:', dict2)
dict1: {'rauf': 81, 'arif': 90, 'maaz': 100, 'hadeed': 73, 'mujahid': 93} dict2: {'rauf': 81, 'arif': 90, 'maaz': 100, 'hadeed': 73, 'mujahid': 93}
copy.copy()
method of copy module to create a shallow copy of List objects in our previous sessioncopy()
method of List and Dictionary objects.import copy
dict1 = {'rauf': 81,
'arif':90,
'maaz':76,
'hadeed':73,
'mujahid':93,
}
#dict2 = copy.copy(dict1)
dict2 = dict1.copy()
# Both variables point to different memory objects, so have the different ID
print('ID of dict1:', id(dict1))
print('ID of dict2:', id(dict2))
ID of dict1: 140419640424064 ID of dict2: 140419640545856
# If you modify an element of one object, the change will NOT be visible in other
dict2["maaz"] = 100
print('\ndict1:', dict1)
print('dict2:', dict2)
dict1: {'rauf': 81, 'arif': 90, 'maaz': 76, 'hadeed': 73, 'mujahid': 93} dict2: {'rauf': 81, 'arif': 90, 'maaz': 100, 'hadeed': 73, 'mujahid': 93}
This seems woking fine, then why this is called shallow copy
Limitation of Shallow Copy
import copy
dict1 = {'rauf': 81,
'arif':90,
'maaz':[55, 66, 77], #note we have a list of marks as a dictionary value
'hadeed':73,
'mujahid':93,
}
#dict2 = copy.copy(dict1)
dict2 = dict1.copy()
# Both variables point to different memory objects, so have the different ID
print('ID of dict1:', id(dict1))
print('ID of dict2:', id(dict2))
ID of dict1: 140419668402752 ID of dict2: 140419668423104
# If you modify a nested element of one object, the change will be visible in both
# This is the limitation of shallow copy
dict2["maaz"][1] = 0
print('\ndict1:', dict1)
print('\ndict2:', dict2)
dict1: {'rauf': 81, 'arif': 90, 'maaz': [55, 0, 77], 'hadeed': 73, 'mujahid': 93} dict2: {'rauf': 81, 'arif': 90, 'maaz': [55, 0, 77], 'hadeed': 73, 'mujahid': 93}
copy.deepcopy()
Method¶import copy
dict1 = {'rauf': 81,
'arif':90,
'maaz':[55, 66, 77],
'hadeed':73,
'mujahid':93,
}
dict2 = copy.deepcopy(dict1)
# Both variables point to different memory objects, so have the different ID
print('ID of dict1:', id(dict1))
print('ID of dict2:', id(dict2))
ID of dict1: 140419640545856 ID of dict2: 140419640435712
# If you modify a nested element of one object, the change will be visible in other
dict2["maaz"][1] = 0
print('\ndict1:', dict1)
print('\ndict2:', dict2)
dict1: {'rauf': 81, 'arif': 90, 'maaz': [55, 66, 77], 'hadeed': 73, 'mujahid': 93} dict2: {'rauf': 81, 'arif': 90, 'maaz': [55, 0, 77], 'hadeed': 73, 'mujahid': 93}
Try answering the following questions to test your understanding of the topics covered in this notebook:
.get
method of a dictionary used for?10.Describe/Differentiate the concept of aliasing, shallow copy and deep copy using assignment statement, dict.copy()
, copy.copy()
and copy.deepcopy()
methods
11.Practice sorting dictionaries having different types of key:value
combinations