4. Learning Python in a Network Context – Network Programmability and Automation [Book]
Understanding the for Loop
for
loops in Python are awesome because when you use them you are usually looping, or iterating, over a set of objects, like those found in a list, string, or dictionary. for
loops in other programming languages require an index and increment value to always be specified, which is not the case in Python.
Letâs start by reviewing what is sometimes called a for-in or for-each loop, which is the more common type of for
loop in Python.
As in the previous sections, we start by reviewing a few basic examples.
The first is to print each object within a list. You can see in the following example that the syntax is simple, and again, much like what we learned when using conditionals and the while
loop. The first statement or beginning of the for
loop needs to end with a colon (:
) and the code to be executed must be indented.
>>>
vendors
[
'arista'
,
'juniper'
,
'big_switch'
,
'cisco'
]
>>>
>>>
for
vendor
in
vendors
:
...
(
'VENDOR: '
+
vendor
)
...
VENDOR
:
arista
VENDOR
:
juniper
VENDOR
:
big_switch
VENDOR
:
cisco
>>>
As mentioned earlier, this type of for
loop is often called a for-in or for-each loop because you are iterating over each element in a given object.
In the example, the name of the object vendor
is totally arbitrary and up to the user to define, and for each iteration, vendor
is equal to that specific element. For example, in this example vendor
equals arista
during the first iteration, juniper
in the second iteration, and so on.
To show that vendor
can be named anything, letâs rename it to be network_vendor
.
>>>
for
network_vendor
in
vendors
:
...
(
'VENDOR: '
+
network_vendor
)
...
VENDOR
:
arista
VENDOR
:
juniper
VENDOR
:
big_switch
VENDOR
:
cisco
>>>
Letâs now combine a few of the things learned so far with containment, conditionals, and loops.
The next example defines a new list of vendors
. One of them is a great company, but just not cut out to be a network vendor! Then it defines approved_vendors
, which is basically the proper, or approved, vendors for a given customer. This example loops through the vendors to ensure they are all approved, and if not, prints a statement saying so to the terminal.
>>>
vendors
=
[
'arista'
,
'juniper'
,
'big_switch'
,
'cisco'
,
'oreilly'
]
>>>
>>>
approved_vendors
=
[
'arista'
,
'juniper'
,
'big_switch'
,
'cisco'
]
>>>
>>>
for
vendor
in
vendors
:
...
if
vendor
not
in
approved_vendors
:
...
(
'NETWORK VENDOR NOT APPROVED: '
+
vendor
)
...
NETWORK
VENDOR
NOT
APPROVED
:
oreilly
>>>
You can see that not
can be used in conjunction with in
, making it very powerful and easy to read what is happening.
Weâll now look at a more challenging example where we loop through a dictionary, while extracting data from another dictionary, and even get to use some built-in methods you learned earlier in this chapter.
To prepare for the next example, letâs build a dictionary that stores CLI commands to configure certain features on a network device:
>>>
COMMANDS
=
{
...
'description'
:
'description {}'
,
...
'speed'
:
'speed {}'
,
...
'duplex'
:
'duplex {}'
,
...
}
>>>
>>>
(
COMMANDS
)
{
'duplex'
:
'duplex {}'
,
'speed'
:
'speed {}'
,
'description'
:
'description {}'
}
>>>
We see that we have a dictionary that has three items (key-value pairs). Each itemâs key is a network feature to configure, and each itemâs value is the start of a command string thatâll configure that respective feature. These features include speed, duplex, and description. The values of the dictionary each have curly braces ({}
) because weâll be using the format()
method of strings to insert variables.
Now that the COMMANDS
dictionary is created, letâs create a second dictionary called CONFIG_PARAMS
that will be used to dictate which commands will be executed and which value will be used for each command string defined in COMMANDS
.
>>>
CONFIG_PARAMS
=
{
...
'description'
:
'auto description by Python'
,
...
'speed'
:
'10000'
,
...
'duplex'
:
'auto'
...
}
>>>
We will now use a for
loop to iterate through CONFIG_PARAMS()
using the items
built-in method for dictionaries. As we iterate through, weâll use the key from CONFIG_PARAMS
and use that to get
the proper value, or command string, from COMMANDS
. This is possible because they were prebuilt using the same key structure. The command string is returned with curly braces, but as soon as itâs returned, we use the format()
method to insert the proper value, which happens to be the value in CONFIG_PARAMS
.
Letâs a take a look.
>>>
commands_list
=
[]
>>>
>>>
for
feature
,
value
in
CONFIG_PARAMS
.
items
():
...
command
=
COMMANDS
.
get
(
feature
)
.
format
(
value
)
...
commands_list
.
append
(
command
)
...
>>>
commands_list
.
insert
(
0
,
'interface Eth1/1'
)
>>>
>>>
(
commands_list
)
[
'interface Eth1/1'
,
'duplex auto'
,
'speed 10000'
,
'description auto description by Python'
]
>>>
Now weâll walk through this in even more detail. Please take your time and even test this out yourself while on the Python interactive interpreter.
In the first line commands_list
is creating an empty list []
. This is required in order to append()
to this list later on.
We then use the items()
built-in method as we loop through CONFIG_PARAMS
. This was covered very briefly earlier in the chapter, but items()
is giving you, the network developer, access to both the key and value of a given key-value pair at the same time. This example iterates over three key-value pairs, namely description/auto description by Python, speed/10000, and duplex/auto.
During each iterationâthat is, for each key-value pair that is being referred to as the variables feature
and value
âa command is being pulled from the COMMANDS
dictionary. If you recall, the get()
method is used to get the value of a key-value pair when you specify the key. In the example, this key is the feature
object. The value being returned is description {}
for description
, speed {}
for speed
, and duplex {}
for duplex
. As you can see, all of these objects being returned are strings, so then we are able to use the format()
method to insert the value
from CONFIG_PARAMS
because we also saw earlier that multiple methods can be used together on the same line!
Once the value is inserted, the command is appended to commands_list
. Once the commands are built, we insert()
Eth1/1
. This could have also been done first.
If you understand this example, you are at a really good point already with getting a grasp on Python!
Youâve now seen some of the most common types of for
loops that allow you to iterate over lists and dictionaries. Weâll now take a look at another way to construct and use a for
loop.
Using the enumerate() function
Occasionally, you may need to keep track of an index value as you loop through an object. We show this fairly briefly, since most examples that are reviewed are like the previous examples already covered.
enumerate()
is used to enumerate the list and give an index value, and is often handy to determine the exact position of a given element.
The next example shows how to use enumerate()
within a for
loop. Youâll notice that the beginning part of the for
loop looks like the dictionary examples, only unlike items()
, which returns a key and value, enumerate()
returns an index, starting at 0, and the object from the list that you are enumerating.
The example prints both the index and value to help you understand what it is doing:
>>>
vendors
=
[
'arista'
,
'juniper'
,
'big_switch'
,
'cisco'
]
>>>
>>>
for
index
,
each
in
enumerate
(
vendors
):
...
(
index
+
' '
+
each
)
...
0
arista
1
juniper
2
big_switch
3
cisco
>>>
Maybe you donât need to print all of indices and values out. Maybe you only need the index for a given vendor. This is shown in the next example.
>>>
for
index
,
each
in
enumerate
(
vendors
):
...
if
each
==
'arista'
:
...
(
'arista index is: '
+
index
)
...
arista
index
is
:
0
>>>
Weâve covered quite a bit of Python so far, from data types to conditionals to loops. However, we still havenât covered how to efficiently reuse code through the use of functions. This is what we cover next.