Python offers a wide range of data types that allow you to efficiently organize and process information. Among them, collections of data stand out: dictionaries, tuples, and sets. In this part, we will take a detailed look at how to use these structures to store and manipulate data in real-world projects. You will learn how to create dictionaries with key-value pairs for convenient access to information, how to use tuples to store ordered sets of data, and how to use sets to work with unique elements.
Dictionaries are an ordered, mutable data type:
data in a dictionary is a key: value pair
access to values is done by key, not by number, as in lists
data in a dictionary is ordered by the order in which elements are added
since dictionaries are mutable, dictionary elements can be changed, added, deleted
key must be an object of immutable type: number, string, tuple
value can be data of any type
In other programming languages, a data type similar to a dictionary may be called an associative array, hash, or hash table.
Example dictionary:
london = {'name': 'London1', 'location': 'London Str', 'vendor': 'Cisco'}
You can also write it like this:
london = {
'id': 1,
'name': 'London',
'it_vlan': 320,
'user_vlan': 1010,
'mngmt_vlan': 99,
'to_name': None,
'to_id': None,
'port': 'G1/0/11'
}
To get a value from the dictionary, you need to refer to the key, just like in lists, only the key will be used instead of the number:
In [1]: london = {'name': 'London1', 'location': 'London Str'}
In [2]: london['name']
Out[2]: 'London1'
In [3]: london['location']
Out[3]: 'London Str'
Similarly, you can add a new key-value pair:
In [4]: london['vendor'] = 'Cisco'
In [5]: print(london)
{'vendor': 'Cisco', 'name': 'London1', 'location': 'London Str'}
In the dictionary, you can use the dictionary as a value:
london_co = {
'r1': {
'hostname': 'london_r1',
'location': '21 New Globe Walk',
'vendor': 'Cisco',
'model': '4451',
'ios': '15.4',
'ip': '10.255.0.1'
},
'r2': {
'hostname': 'london_r2',
'location': '21 New Globe Walk',
'vendor': 'Cisco',
'model': '4451',
'ios': '15.4',
'ip': '10.255.0.2'
},
'sw1': {
'hostname': 'london_sw1',
'location': '21 New Globe Walk',
'vendor': 'Cisco',
'model': '3850',
'ios': '3.6.XE',
'ip': '10.255.0.101'
}
}
You can get a value from a nested dictionary like this:
In [7]: london_co['r1']['ios'] Out[7]: '15.4' In [8]: london_co['r1']['model'] Out[8]: '4451' In [9]: london_co['sw1']['ip'] Out[9]: '10.255.0.101'
The sorted function sorts the keys of a dictionary in ascending order and returns a new list with the sorted keys:
In [1]: london = {'name': 'London1', 'location': 'London Str', 'vendor': 'Cisco'}
In [2]: sorted(london)
Out[2]: ['location', 'name', 'vendor']
clearThe clear method allows you to clear the dictionary:
In [1]: london = {'name': 'London1', 'location': 'London Str'}
In [2]: london.clear()
In [3]: london
Out[3]: {}
copyThe copy method allows you to create a complete copy of a dictionary.
If you specify that one dictionary is equal to another:
In [4]: london = {'name': 'London1', 'location': 'London Str', 'vendor': 'Cisco'}
In [5]: london2 = london
In [6]: id(london)
Out[6]: 25489072
In [7]: id(london2)
Out[7]: 25489072
In [8]: london['vendor'] = 'Juniper'
In [9]: london2['vendor']
Out[9]: 'Juniper'
In this case, london2 is another name that refers to the dictionary. And when the dictionary london changes, the dictionary london2 changes too, because it is a reference to the same object.
So if you want to make a copy of the dictionary, you need to use the copy() method:
In [10]: london = {'name': 'London1', 'location': 'London Str', 'vendor': 'Cisco'}
In [11]: london2 = london.copy()
In [12]: id(london)
Out[12]: 25524512
In [13]: id(london2)
Out[13]: 25563296
In [14]: london['vendor'] = 'Juniper'
In [15]: london2['vendor']
Out[15]: 'Cisco'
getIf, when accessing the dictionary, a key is specified that is not in the dictionary, an error occurs:
In [16]: london = {'name': 'London1', 'location': 'London Str', 'vendor': 'Cisco'}
In [17]: london['ios']
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-17-b4fae8480b21> in <module>()
----> 1 london['ios']
KeyError: 'ios'
The get method asks for the key, and if it doesn’t exist, it returns None instead of an error.
In [18]: london = {'name': 'London1', 'location': 'London Str', 'vendor': 'Cisco'}
In [19]: print(london.get('ios'))
None
The get() method also allows you to specify a different value instead of None:
In [20]: print(london.get('ios', 'Ooops'))
Ooops
setdefaultThe setdefault method looks for the key, and if it doesn’t exist, it creates a key with the value None instead of an error.
In [21]: london = {'name': 'London1', 'location': 'London Str', 'vendor': 'Cisco'}
In [22]: ios = london.setdefault('ios')
In [23]: print(ios)
None
In [24]: london
Out[24]: {'name': 'London1', 'location': 'London Str', 'vendor': 'Cisco', 'ios': None}
If the key exists, setdefault returns a value that corresponds to:
In [25]: london.setdefault('name')
Out[25]: 'London1'
The second argument allows you to specify what value should correspond to the key:
In [26]: model = london.setdefault('model', 'Cisco3580')
In [27]: print(model)
Cisco3580
In [28]: london
Out[28]:
{'name': 'London1',
'location': 'London Str',
'vendor': 'Cisco',
'ios': None,
'model': 'Cisco3580'}
The setdefault method replaces the following construct:
In [30]: if key in london:
...: value = london[key]
...: else:
...: london[key] = 'somevalue'
...: value = london[key]
...:
keys, values, itemsKeys, values, items methods:
In [24]: london = {'name': 'London1', 'location': 'London Str', 'vendor': 'Cisco'}
In [25]: london.keys()
Out[25]: dict_keys(['name', 'location', 'vendor'])
In [26]: london.values()
Out[26]: dict_values(['London1', 'London Str', 'Cisco'])
In [27]: london.items()
Out[27]: dict_items([('name', 'London1'), ('location', 'London Str'), ('vendor', 'Cisco')])
All three methods return special view objects that represent the keys, values, and key-value pairs of the dictionary, respectively. A very important feature of views is that they change as the dictionary changes.
For example, in the keys method:
In [28]: london = {'name': 'London1', 'location': 'London Str', 'vendor': 'Cisco'}
In [29]: keys = london.keys()
In [30]: print(keys)
dict_keys(['name', 'location', 'vendor'])
Now the variable keys corresponds to the view dict_keys, which has three keys: name, location, and vendor.
If we add another key-value pair to the dictionary, the keys object will also change:
In [31]: london['ip'] = '10.1.1.1' In [32]: keys Out[32]: dict_keys(['name', 'location', 'vendor', 'ip'])
If you need to get a regular list of keys that won’t change with changes to the dictionary, just convert the view to a list:
In [33]: list_keys = list(london.keys()) In [34]: list_keys Out[34]: ['name', 'location', 'vendor', 'ip']
delDelete key and value:
In [35]: london = {'name': 'London1', 'location': 'London Str', 'vendor': 'Cisco'}
In [36]: del london['name']
In [37]: london
Out[37]: {'location': 'London Str', 'vendor': 'Cisco'}
updateThe update method allows you to add the contents of another dictionary to the dictionary:
In [38]: r1 = {'name': 'London1', 'location': 'London Str'}
In [39]: r1.update({'vendor': 'Cisco', 'ios':'15.2'})
In [40]: r1
Out[40]: {'name': 'London1', 'location': 'London Str', 'vendor': 'Cisco', 'ios': '15.2'}
You can update the values in a similar way:
In [41]: r1.update({'name': 'london-r1', 'ios':'15.4'})
In [42]: r1
Out[42]:
{'name': 'london-r1',
'location': 'London Str',
'vendor': 'Cisco',
'ios': '15.4'}
A dictionary can be created using a literal:
In [1]: r1 = {'model': '4451', 'ios': '15.4'}
The dict constructor allows you to create a dictionary in several ways.
If you use strings as keys, you can use the following way of creating a dictionary:
In [2]: r1 = dict(model='4451', ios='15.4')
In [3]: r1
Out[3]: {'model': '4451', 'ios': '15.4'}
The second option for creating a dictionary using dict:
In [4]: r1 = dict([('model', '4451'), ('ios', '15.4')])
In [5]: r1
Out[5]: {'model': '4451', 'ios': '15.4'}
In a situation where you need to create a dictionary with known keys, but for now empty values (or identical values), the fromkeys() method is very convenient:
In [5]: d_keys = ['hostname', 'location', 'vendor', 'model', 'ios', 'ip']
In [6]: r1 = dict.fromkeys(d_keys)
In [7]: r1
Out[7]:
{'hostname': None,
'location': None,
'vendor': None,
'model': None,
'ios': None,
'ip': None}
By default, the fromkeys method substitutes the value None. But you can also specify your own value:
In [8]: router_models = ['ISR2811', 'ISR2911', 'ISR2921', 'ASR9002']
In [9]: models_count = dict.fromkeys(router_models, 0)
In [10]: models_count
Out[10]: {'ISR2811': 0, 'ISR2911': 0, 'ISR2921': 0, 'ASR9002': 0}
This option for creating a dictionary is not suitable for all cases. For example, using a mutable data type in the value will create a reference to the same object:
In [10]: router_models = ['ISR2811', 'ISR2911', 'ISR2921', 'ASR9002']
In [11]: routers = dict.fromkeys(router_models, [])
...:
In [12]: routers
Out[12]: {'ISR2811': [], 'ISR2911': [], 'ISR2921': [], 'ASR9002': []}
In [13]: routers['ASR9002'].append('london_r1')
In [14]: routers
Out[14]:
{'ISR2811': ['london_r1'],
'ISR2911': ['london_r1'],
'ISR2921': ['london_r1'],
'ASR9002': ['london_r1']}
In this case, each key refers to the same list, so adding a value to one of the lists updates the others.
A tuple in Python is:
a sequence of elements separated by commas and enclosed in parentheses
an immutable ordered data type
Roughly speaking, a tuple is a list that cannot be changed. That is, a tuple has only read permissions. This can be a protection against accidental changes.
Create an empty tuple:
In [1]: tuple1 = tuple() In [2]: print(tuple1) ()
A tuple of one element (note the comma):
In [3]: tuple2 = ('password',)
Tuple from the list:
In [4]: list_keys = ['hostname', 'location', 'vendor', 'model', 'ios', 'ip']
In [5]: tuple_keys = tuple(list_keys)
In [6]: tuple_keys
Out[6]: ('hostname', 'location', 'vendor', 'model', 'ios', 'ip')
Objects in a tuple can be accessed, like list objects, by ordinal number:
In [7]: tuple_keys[0] Out[7]: 'hostname'
But since the tuple is immutable, you can’t assign a new value:
In [8]: tuple_keys[1] = 'test' --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-9-1c7162cdefa3> in <module>() ----> 1 tuple_keys[1] = 'test' TypeError: 'tuple' object does not support item assignment
The sorted function sorts the elements of a tuple in ascending order and returns a new list with the sorted elements:
In [2]: tuple_keys = ('hostname', 'location', 'vendor', 'model', 'ios', 'ip')
In [3]: sorted(tuple_keys)
Out[3]: ['hostname', 'ios', 'ip', 'location', 'model', 'vendor']
Sets are mutable unordered data types. Many always contain only unique elements. Python sets are a sequence of elements separated by commas and enclosed in curly braces.
With Sets, you can easily remove duplicate elements:
In [1]: vlans = [10, 20, 30, 40, 100, 10]
In [2]: set(vlans)
Out[2]: {10, 20, 30, 40, 100}
In [3]: set1 = set(vlans)
In [4]: print(set1)
{40, 100, 10, 20, 30}
add()The add() method adds an element to a set:
In [1]: set1 = {10,20,30,40}
In [2]: set1.add(50)
In [3]: set1
Out[3]: {10, 20, 30, 40, 50}
discard()The discard() method allows you to remove elements without throwing an error if the element is not in the set:
In [3]: set1
Out[3]: {10, 20, 30, 40, 50}
In [4]: set1.discard(55)
In [5]: set1
Out[5]: {10, 20, 30, 40, 50}
In [6]: set1.discard(50)
In [7]: set1
Out[7]: {10, 20, 30, 40}
clear()The clear() method clears a set:
In [8]: set1 = {10,20,30,40}
In [9]: set1.clear()
In [10]: set1
Out[10]: set()
Many are useful because you can perform various operations on them and find the union of sets, intersection, and so on.
The union of sets can be obtained using the union() method or the | operator:
In [1]: vlans1 = {10, 20, 30, 50, 100}
In [2]: vlans2 = {100, 101, 102, 200}
In [3]: vlans1.union(vlans2)
Out[3]: {10, 20, 30, 50, 100, 101, 102, 200}
In [4]: vlans1 | vlans2
Out[4]: {10, 20, 30, 50, 100, 101, 102, 200}
The intersection of sets can be obtained using the intersection() method or the & operator:
In [5]: vlans1 = {10, 20, 30, 50, 100}
In [6]: vlans2 = {100, 101, 102, 200}
In [7]: vlans1.intersection(vlans2)
Out[7]: {100}
In [8]: vlans1 & vlans2
Out[8]: {100}
You cannot create an empty set using a literal (because in that case it would not be a set, but a dictionary):
In [1]: set1 = {}
In [2]: type(set1)
Out[2]: dict
But an empty set can be created like this:
In [3]: set2 = set() In [4]: type(set2) Out[4]: set
Set from the string:
In [5]: set('long long long long string')
Out[5]: {' ', 'g', 'i', 'l', 'n', 'o', 'r', 's', 't'}
Plural from the list:
In [6]: set([10, 20, 30, 10, 10, 30])
Out[6]: {10, 20, 30}
Dictionaries, tuples, and sets are important data structures in Python, each with its own unique features and applications.
Dictionaries store key:value pairs and provide fast access to data by key. They are suitable for cases where you need to store linked data and have fast access to it.
Tuples are immutable sequences, which allows them to be used as keys in dictionaries or to store data that should not change. This makes them useful for protecting information from accidental changes.
Sets store unique elements and support fast union, intersection, and difference operations. They are suitable for removing duplicates and efficiently handling unique data.
Proper use of these structures allows you to optimize data storage and processing in Python, ensuring efficiency and readability of the code.