Site icon Karneliuk

From Python to Go 006. Dictionaries and Maps.

Hello my friend,

We continue our journey from Python to Go (Golang), or more right to say with Python and Go (Golang) together. Today we are going to talk about a data structure, which is by far the most widely used in Python when it comes to a network and IT infrastructure automation and management. This data structure is called dictionaries in Python, or Map in Go (Golang).

Black Friday Is Over, Can I Still Buy Your Trainings?

Of course, you can. Our self-paced network automation trainings are the perfect place to start your journey in network and IT infrastructure automation or to upskill yourself further if you are seasoned engineer. There is no such thing as excessive knowledge, therefore we encourage you to join our network automation programs and start your study today:

We offer the following training programs in network automation for you:

During these trainings you will learn the following topics:

Moreover, we put all mentions technologies in the context of real use cases, which our team has solved and are solving in various projects in the service providers, enterprise and data centre networks and systems across the Europe and USA. That gives you opportunity to ask questions to understand the solutions in-depth and have discussions about your own projects. And on top of that, each technology is provided with online demos and labs to master your skills thoroughly. Such a mixture creates a unique learning environment, which all students value so much. Join us and unleash your potential.

Start your automation training today.

What Are We Going To Talk Today About?

I remember myself starting with Python long ago back in 2015 and how I was amazed by dictionaries. They are beautiful and truly powerful if you know when and how to use them. I hope you will be (or are) amazed as I am, and to make this happen we’ll discuss the following topics:

  1. What is dictionary/map in general?
  2. What are its similarities and differences from list? Where to use which data type?
  3. How to use dictionary/map in your Python and Go (Golang) code?

Explanation

In a nutshell, dictionary in Python is data structure consisting of key-value pairs, where key is typically a string (although it cloud be other data type, such as boolean, number and even tuple) and value is virtually anything: string, number, boolean, list, another dictionary or even function. From look and feel perspective it is very similar to list, but you have a convenience to use a meaningful name as indexes rather than just integers.

With Go (Golang) being statically typed, you have to specify upfront what data type you are going to use, and all your keys and variables must be of data type you define. There is a trick here, which called interfaces, which allows you to use any data type for value, but we’ll touch it in a separate blog post. By the say, Go (Golang) doesn’t use term dictionary, but it uses term map instead.

Other programming languages may use different terminology. For example, Perl uses term hash, whilst C doesn’t have such concept at all with hash-table being the closest data structure.

As we mentioned before, dictionaries are very similar to lists/slices in their capabilities and ways how we interact with them. As such, typical operations are:

In contrast to list/slice, you typically don’t sort order of keys in dictionary/map. In fact, in Python there is a dedicated data structure called OrderedDict, which intents to have keys ordered in whatever way. In Go (Golang), keys are by default sorted in alphabetical order, when strings are used.

As picture costs thousand words, let’s put all these concepts in motion.

Examples

The following scenario will serve the purpose of developing a demonstration piece of code both in Python and Go (Golang):

  1. You will have a list of dictionaries/maps, which acts as an inventory.
  2. First of all, we’ll loop through every element in this list to get access to these dictionaries/maps.
  3. For each dictionary/map we’ll perform all typical operations explained before.

As we are going to focus on dictionary part, we suggest you to review first list/slices and loop/conditionals blog posts from this series.

Python

Let’s review the sample code for Python first:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
"""From Python to Go: Python: 005 - Dictionaries and Maps"""

# Variables
inventory = [
    {
        "name": "leaf-01",
        "os": "cisco-nxos",
        "ip": "192.168.1.1",
    },
    {
        "name": "leaf-02",
        "os": "arista-eos",
        "ip": "192.168.1.2",
    },
    {
        "name": "spine-01",
        "ip": "192.168.1.1",
    },
]


# Execution
if __name__ == "__main__":
    # Loop through all network devices
    for d in inventory:
        # Print the device data
        print(d)

        # Print the hostname
        print(f"Hostname: {d['name']}")

        # Add the OS key if it is missing
        if "os" not in d:
            d["os"] = None
        print(d)

        # Add new key-value pair
        d["location"] = "DC1"
        print(d)

        # Remove the IP key
        d.pop("ip")
        print(d)

        # Go through all keys and values
        for k, v in d.items():
            print(f"{k}: {v}")

    # Print the inventory after modifications
    print(inventory)

The first thing you may see different is the notations of dictionary: its content is wrapped inside curly braces “{}“, which is different to content of the list, which is wrapped inside the square braces “[]“. The key-value pairs are provided in the format “‘key’: ‘value’” and are separated by comma from each other. We’ve put them one key-value pair at time line to simplify visual understanding. As the key is the sting, it is put in quotes, as any other string. The same syntax is in Go (Golang), by the way.

Some further explanations:

  1. In order to access specific key from the dictionary, you use “dict_name[“key_name”]” syntax. This is also applicable if you want to change content of the existing key or create a new key, but in these cases you also need to provide a new value after “=“.
  2. To delete the key from dictionary, you can use either “.pop()” method as provided or “del dict[“key_name”]” instruction.
  3. If you want to check, if certain key exists in dictionary in Python, you use if-conditional where you look literally for the name of the key within the dictionary: “if “key_name” not in dictionary” (you may also omit “not” depending on your logic).
  4. To loop through all the elements in the dictionary you use “.items()” method applied to dictionary. This method returns iterator with key and value elements in separate variables.

Let’s see the execution results of this Python application:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ python3.10 main.py
{'name': 'leaf-01', 'os': 'cisco-nxos', 'ip': '192.168.1.1'}
Hostname: leaf-01
{'name': 'leaf-01', 'os': 'cisco-nxos', 'ip': '192.168.1.1'}
{'name': 'leaf-01', 'os': 'cisco-nxos', 'ip': '192.168.1.1', 'location': 'DC1'}
{'name': 'leaf-01', 'os': 'cisco-nxos', 'location': 'DC1'}
name: leaf-01
os: cisco-nxos
location: DC1
{'name': 'leaf-02', 'os': 'arista-eos', 'ip': '192.168.1.2'}
Hostname: leaf-02
{'name': 'leaf-02', 'os': 'arista-eos', 'ip': '192.168.1.2'}
{'name': 'leaf-02', 'os': 'arista-eos', 'ip': '192.168.1.2', 'location': 'DC1'}
{'name': 'leaf-02', 'os': 'arista-eos', 'location': 'DC1'}
name: leaf-02
os: arista-eos
location: DC1
{'name': 'spine-01', 'ip': '192.168.1.1'}
Hostname: spine-01
{'name': 'spine-01', 'ip': '192.168.1.1', 'os': None}
{'name': 'spine-01', 'ip': '192.168.1.1', 'os': None, 'location': 'DC1'}
{'name': 'spine-01', 'os': None, 'location': 'DC1'}
name: spine-01
os: None
location: DC1
[{'name': 'leaf-01', 'os': 'cisco-nxos', 'location': 'DC1'}, {'name': 'leaf-02', 'os': 'arista-eos', 'location': 'DC1'}, {'name': 'spine-01', 'os': None, 'location': 'DC1'}]

It is worth mentioning that modification of the dictionary whilst you loop over the higher-level list is propagated back to the original list. I’m sure you’ve noticed that in the snippet we have deleted one key and added another one. As a result, the original inventory was modified.

Go (Golang)

That was Python, now let’s convert it to Go (Golang) code:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/* From Python to Go: Python: 006 - Dictionaries and Maps */
package main

import (
    "fmt"
)

func main() {
    // Define inventory
    inventory := []map[string]string{
        {
            "name": "leaf-01",
            "os":   "cisco-nxos",
            "ip":   "192.168.1.1",
        }, {
            "name": "leaf-02",
            "os":   "arista-eos",
            "ip":   "192.168.1.2",
        }, {
            "name": "spine-01",
            "ip":   "192.168.1.1",
        },
    }

    // Loop through all network devices
    for _, d := range inventory {
        // Print the device data
        fmt.Println(d)

        // Print the hostname
        fmt.Printf("Hostname: %v\n", d["name"])

        // Add the OS key if it is missing
        if _, ok := d["os"]; !ok {
            d["os"] = ""
        }
        fmt.Println(d)

        // Add new key-value pair
        d["location"] = "DC1"
        fmt.Println(d)

        // Remove the IP key
        delete(d, "ip")
        fmt.Println(d)

        // Go through all keys and values
        for k, v := range d {
            fmt.Printf("%v: %v\n", k, v)
        }
    }
    fmt.Println(inventory)
}

Breakdown:

  1. As already mentioned earlier in this blog post, Go is strict typed. As such, you’d need to specify the type of our inventory, which we define as “[]map[string]string“, what means:
    • []” is a slice, as discussed before.
    • map[string]string” of maps, which use string data type for keys and string data type for values.
  2. Accessing specific key within map, as well as changing its value or creating a new key is identical to Python and is achieved by calling “map[“key_name”]“.
  3. Checking if key exist in map is done via conditional if; however, the syntax is different to Python:
    • 2 variables are return as the result of declaration: first value is variable, which you can put in special vaiable “_” meaning you aren’t interested in it, and the second variable is of boolean type returning true if key exists and false if it doesn’t. Commonly it is called “ok“.
    • The conditional “!ok” means negation, so that the condition is true when “ok” is false. Essentially, “!” in Go (Golang) equals to Python “not” statement.
  4. To delete the the key from the map, function “delete()” is used, which takes 2 arguments: the name of the map and the name of the key to delete.
  5. In order to iterate over all key-value pairs, the same operator “range” is used, as for iterating over the list elements.

Execution of the Go (Golang) code provide the same result as Python’s one.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ go run .
map[ip:192.168.1.1 name:leaf-01 os:cisco-nxos]
Hostname: leaf-01
map[ip:192.168.1.1 name:leaf-01 os:cisco-nxos]
map[ip:192.168.1.1 location:DC1 name:leaf-01 os:cisco-nxos]
map[location:DC1 name:leaf-01 os:cisco-nxos]
name: leaf-01
os: cisco-nxos
location: DC1
map[ip:192.168.1.2 name:leaf-02 os:arista-eos]
Hostname: leaf-02
map[ip:192.168.1.2 name:leaf-02 os:arista-eos]
map[ip:192.168.1.2 location:DC1 name:leaf-02 os:arista-eos]
map[location:DC1 name:leaf-02 os:arista-eos]
name: leaf-02
os: arista-eos
location: DC1
map[ip:192.168.1.1 name:spine-01]
Hostname: spine-01
map[ip:192.168.1.1 name:spine-01 os:]
map[ip:192.168.1.1 location:DC1 name:spine-01 os:]
map[location:DC1 name:spine-01 os:]
name: spine-01
os:
location: DC1
[map[location:DC1 name:leaf-01 os:cisco-nxos] map[location:DC1 name:leaf-02 os:arista-eos] map[location:DC1 name:spine-01 os:]]

Same remark as in Python is applicable here: whenever you change content of maps whilst looping through list, the changes are reflected in the original list.

Lessons in GitHub

You can find the final working versions of the files from this blog at out GitHub page.

Conclusion

By this point we have covered majority of data types, which you will face upon developing applications in Python and Go (Golang). I would say, we covered all “basic”, although it is not very scientific word. In the next blog post we will cover the last data type, which is of paramount importance in Go (Golang) and is also very important in Python. Continue labbing, continue studding. Take care and good bye.

Support us






P.S.

If you have further questions or you need help with your networks, I’m happy to assist you, just send me message. Also don’t forget to share the article on your social media, if you like it.

BR,

Anton Karneliuk 

Exit mobile version