Site icon Karneliuk

CEX (Code EXpress) 10. Creating user functions.

Hello my friend,

So far you have learned the most vital tools to start writing your code in Python such as Python’s variables, lists, dictionary data constructions and code flow control for, while and if. Today you will see how to join them all together to create a user defined functions to make your Python’s code cleaner and less error-prone.

Network automation training – boost your career

Don’t wait to be kicked out of IT business. Join our network automation training to secure your job in future. Come to NetDevOps side.

How does the training differ from this blog post series? Here you get the basics and learn some programming concepts in general, whereas in the training you get comprehensive set of knowledge with the detailed examples how to use Python for the network and IT automation. You need both.

What are we going to do today?

User-defined functions is a reusable parts of the Python’s code, which allow you create some processing once in your code and then call it multiple types anywhere you need. So you will learn:

You have already seen the predefined functions, such as print(), split() and join(). The idea behind a user-defined function is create choose_your_name(chosse_args) function, which can do some useful processing for you. This created function will be used in your Python’s program further pretty much in the same way as any other built-in function.

We create all the example in Python 3.8. If you need guidance how to set up it and use it, check the first blogpost in CEX series.

Why does it matter?

Using the example of the previous blogpost you can see, that we have copied similar code several time, when we did same tasks. Namely, to convert an IP address in a string format, we used its conversion to array and then math operation to convert for the first and the last IP addresses in the range. And we have copied the Python’s code with all the associated transformations multiple times. In case we need to modify the logic, we would need to do the code’s change multiple times in all the places we use that.

And that is exact the reason of creating any user-defined function. You create a framework, which can do the processing of the certain inputs and generate the certain outputs. If you like, you can think about it as a mini program inside your main program. And you call this program every time, when you need to do a certain computation or processing. Such an approach makes your code less error-prone, as you can focus on the code of the user-defined function once, during its development, and test it thoroughly, and don’t focus any on it anymore, but rather to focus on the logic if you Python’s program.

Looking back to the previous blogpost, we did:

The immediate improvement of our previous script could be a creation of the user-defined function for the first operation, which should take string as an input argument and return the integer as a result.

The second improvement is an extending the function’s input arguments so that it can take two of them: the first one defines the operation (string to integer or integer to string) and the second one contains the value of the string or integer correspondingly. The result of this function’s execution should be either the integer or string, depending on the operation type.

How are we doing that?

As this is already the 10th blogpost, we don’t see why we need to change the structure We create a new directory containing this Python script in our GitHub Python’s lessons repository:


1
2
3
4
$ cd CEX
$ mkdir 10
$ cd 10
$

In that directory we create a Python’s file with the name def.py, which we will work on today:


1
2
3
$ touch def.py && chmod a+x def.py
$ cat def.py
#!/usr/local/bin/python3.8

The Python’s file should be executable inside the Linux that’s why we use chmod command.

You might be thinking, why we call the file def.py. The answer is that keyword def is used to create a user defined functions, per the syntax below:


1
2
3
4
5
6
def your_function(arg1, arg2, .., argN):
    actions with arg1, arg2, .., argN
    ...
    return some_result

your_result = your_function(var_a, var_b, .., varN)

Now you know how to compose the user-defined functions in theory, so we need to put it into practice.

#1. Creating simple user-defined function

The starting point for this exercise is the code from the previous session, and the first improvement is creation of the function to covert the dotted-decimal notation of the IP address in the string format into an integer value. The original code has no user-defined functions:


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
$ cat ../09/while.py
#!/usr/local/bin/python3.8

# Variables
ip_addresses = '10.0.0.3-10.0.1.15'


# Body
ip_start, ip_end = ip_addresses.split('-')

ip_start = ip_start.split('.')
index = len(ip_start) - 1
num_ip_s = 0

while index >= 0:
    num_ip_s += (int(ip_start[index]) * (256 ** (len(ip_start) - 1 - index)))
    index -= 1

ip_end = ip_end.split('.')
index = len(ip_end) - 1
num_ip_e = 0

while index >= 0:
    num_ip_e += (int(ip_end[index]) * (256 ** (len(ip_end) - 1 - index)))
    index -= 1

As you can see, we repeat the same set of the actions for the ip_start and ip_end variables. In such a case, the creation of the user-defined function has a perfect sense. The input to the function, as mentioned above, should be the string value: ip_start and ip_end. The output of the function should be the integer value, which is due to be stored in the num_ip_s or num_ip_e variables correspondingly.

After creation of the user-defined functions, the code is changed to the following 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
27
$ cat ./def.py
#!/usr/local/bin/python3.8

# Variables
ip_addresses = '10.0.0.3-10.0.1.15'


# User-defined functions
def ip_int_str(input_var):
    list_addr = input_var.split('.')
    temp_number = 0
    index = len(list_addr) - 1

    while index >=0:
        temp_number += (int(list_addr[index]) * (256 ** (len(list_addr) - 1 - index)))
        index -= 1

    return temp_number


# Main body
ip_start, ip_end = ip_addresses.split('-')

num_ip_s = ip_int_str(ip_start)
num_ip_e = ip_int_str(ip_end)

print(num_ip_s, num_ip_e)

Despite the name of the function could be anything following the naming convention of the variables, it makes sense to have its name as something meaningful. In the provided case we use the name ip_int_str() what means the conversion of the IP address between the integer and string formats. Currently the function ip_int_str() is due to have a single input argument, which is named in the Python’s code inside the function as input_var.

The result of the functions’s execution is stored in the temp_number variable, which using return keyword are conveyed outside of the function to the variable, which should get the function’s result. In the provided snippet, the names are num_ip_s and num_ip_e.

Let’s take on the result of the new Python’s script containing the user-defined function:


1
2
$ ./def.py
167772163 167772431

The visible advantage is that the second code is shorter. In reality, the biggest advantage is that you need to debug and fix the code only once, when you compose the function. All the time you reuse, it works exactly in the same way.

#2. Extending the user-defined function

The user-defined function is a Python’s code. It can be simple, and it can be complex. The import point here is that this complexity should be justifiable. Let’s think for a moment: we do both the operation to convert the string with IP address to integer and back. So what you can do then, is to extend the created function to make a reverse operation. And to define which operation is needed (string to integer or integer to string) you can use an additional argument. Let’s modify our script above as explained:


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
$ cat def.py
#!/usr/local/bin/python3.8

# Variables
ip_addresses = '10.0.0.3-10.0.1.15'


# User-defined functions
def ip_int_str(operation, input_var):
    if operation == 'get_int':
        list_addr = input_var.split('.')
        temp_number = 0
        index = len(list_addr) - 1

        while index >=0:
            temp_number += (int(list_addr[index]) * (256 ** (len(list_addr) - 1 - index)))
            index -= 1

    elif operation == 'get_str':
        decr = input_var
        index = 0
        temp_number = []

        while decr > 0:
            temp_number.append(str(int(decr / 256 ** (3 - index))))
            decr %= (256 ** (3 - index))
            index += 1

        temp_number = '.'.join(temp_number)

    return temp_number


# Main body
ip_start, ip_end = ip_addresses.split('-')

num_ip_s = ip_int_str('get_int', ip_start)
num_ip_e = ip_int_str('get_int', ip_end)

if num_ip_s <= num_ip_e:
    num_ip_t = num_ip_s

    print('Printing IP in range {}'.format(ip_addresses))

    while num_ip_t <= num_ip_e:
        ip_addr = ip_int_str('get_str', num_ip_t)
        print('IP is {}'.format(ip_addr))

        num_ip_t += 1

else:
    print('The starting IP in the range is higher than the final one.')

As you might spot, we have added the new argument called operation to our user-defined function ip_int_str():

These choices is done using the if conditional. In both cases we use return temp_number, what is the variable containing the result of the both internal computations. As you also can see, now we call the function using two variables: operation and input_var.

Let’s execute this Python’s code and see the results:


1
2
3
4
5
6
7
8
9
$ ./def.py
Printing IP in range 10.0.0.3-10.0.1.15
IP is 10.0.0.3
IP is 10.0.0.4
IP is 10.0.0.5
IP is 10.0.0.6
! Some output is truncated for brevity
IP is 10.0.1.14
IP is 10.0.1.15

The results are exactly the same, as they were the last time. And that is was the goal. However, your Python’s code is much clearer and more “pythonic”.

If you prefer video

If you prefer watching the video instead of reading blogpost, that is also wonderful. We value your time and want to create for you the best experience possible. Therefore, for all the blogposts associated with CEX series, we will record the video and post it on our YouTube channel.

And here is the video for this blogpost:

What else shall you try?

Programming is all around testing, trying, breaking and fixing the things. Try to do the following things to collect some more experience:

Lessons in GitHub

Our GitHub page has the Python’s script from this lesson, like wise from all others as well.

Conclusion

Python is an amazing programming language. We are pretty sure you have seen it from our text. By now you have learned the essential toolkit, which will allow you to navigate in the world of the Python’s programming. The next 10 Python’s lessons will be about more advanced topics. Take care and goodbye!

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