Cisco DevNet Associate course 015 Software Development and Design Explain the benefits of organizing code into Modules
Watch Full Demo on YouTube:
Introduction:
When you’re first learning Python for network automation, it can feel overwhelming to manage growing scripts. That’s where modules and packages come in. They allow you to organize your code into smaller, reusable building blocks, making it easier to read, maintain, and scale.
In this lesson, part of the Cisco DevNet Associate 200-901 DEVASC course, we’ll break down exactly what Python modules are, how to load them into your code, and how packages extend this idea even further. By the end, you’ll understand not only what modules are, but also why they’re such a powerful tool in professional programming and networking automation.
💡What are Modules in Python? And what are the Benefits of Using Them?
A module in Python is simply a file that contains Python code. That code could be functions, classes, or variables that you want to reuse in other programs.
Think of it this way: instead of writing one huge script with everything jammed together, you can split your code into smaller, reusable pieces (modules).
Benefits of using modules:
One of the main reasons Python is so popular in networking and automation is its modular design. By breaking your code into modules, you unlock several practical benefits that make your projects easier to build, scale, and maintain. Let’s go through them one by one.
1. Reusability
Instead of rewriting the same code over and over, you can place it in a module and reuse it anywhere.
For example, if you create a function to validate IP addresses, you can import that module into multiple scripts. This saves time and prevents duplication.
# ip_utils.py
def validate_ip(ip):
# pretend logic here
return True
# main.py
import ip_utils
print(ip_utils.validate_ip("192.168.1.1"))
Write once, use everywhere — that’s the power of reusability.
2. Organization
As projects grow, scripts can become messy if everything is in a single file.
Modules let you separate different logic into dedicated files. For instance, you might keep all your network utility functions in one module, and all your database functions in another.
This makes it easier to navigate your codebase, especially when you come back to it after weeks or months.
3. Maintainability
When code is split into modules, troubleshooting and updates become far easier.
If something goes wrong with your authentication logic, you can head straight to auth_module.py
instead of digging through a giant script.
Smaller, focused modules mean fewer side effects when making changes.
4. Collaboration
If you’re working in a team, modules allow multiple developers to contribute without stepping on each other’s toes.
One person can work on the network_module.py
, while another handles the api_module.py
. Since the code is modular, everything can later be combined into a single, well-structured project.
This is especially valuable in professional environments where version control systems (like Git) are used.
5. Standardization
Python already provides a wealth of built-in modules like datetime
, os
, and sys
. Instead of reinventing the wheel, you can take advantage of these reliable, well-tested tools.
import datetime
print(datetime.date.today()) # Prints today’s date
By relying on standardized modules, you keep your code cleaner, more consistent, and aligned with best practices.
💡How to loading a module in python code
To use a module, you need to import it into your script. The import keyword makes the code inside the module available.
There are several different ways to import modules depending on your needs. Let’s go through them step by step.
1. The Basic import
Statement
The first and most straightforward way is with the basic import
statement.
This loads the entire module, and you access its features using the module name as a prefix.
import math
print(math.sqrt(16)) # 4.0
print(math.pi) # 3.141592653589793
This method is simple and clear, but you always need to type the module name as a prefix (math.
), which can feel a bit long if you’re using it often.
2. Using Aliases with as
To make your code cleaner, you can assign an alias using the as
keyword. This gives the module a shorter name.
import pandas as pd
data = pd.DataFrame({"Name": ["Tarek", "Sarah"], "Age": [35, 30]})
print(data)
This is especially helpful for modules with long names (like pandas
) or ones you’ll use a lot throughout your script.
3. Importing Specific Functions or Classes
Sometimes you don’t need the entire module — just a single function or class.
That’s when you use the from ... import ...
style.
from math import sqrt
print(sqrt(25)) # 5.0
This way you don’t need to prefix with math.
every time. Your code feels lighter and more focused.
4. Importing with Aliases for Functions or Classes
You can also apply an alias to individual imports.
from math import factorial as fact
print(fact(5)) # 120
This keeps your code concise when working with long names, while still being clear about what’s happening.
5. Importing Everything with from ... import *
Finally, there’s the “import all” approach:
from math import *
print(sin(0)) # 0.0
print(pi) # 3.141592653589793
This pulls everything from a module into your script. While convenient in small experiments, it’s generally discouraged for bigger projects because:
- It clutters your namespace (too many variables/functions at once).
- It can cause name conflicts if two modules contain functions with the same name.
Think of it like dumping your entire toolbox onto the floor — quick access, but messy.
Python Packages in Action: Cisco and Juniper Modules
A package in Python is a collection of modules organized in a directory. To turn a folder into a package, you just add an empty __init__.py
file inside it. This lets you group related functionality together, which is especially useful for large projects like network automation.
Let’s build an example package called network_devices
that contains two modules:
cisco_module.py
juniper_module.py
Both modules will use Netmiko to connect to a device, run show commands, and push configuration.
Step 1: Package Structure
network_devices/
__init__.py
cisco_module.py
juniper_module.py
main.py
Step 2: Cisco Module (cisco_module.py
)
from netmiko import ConnectHandler
class CiscoDevice:
def __init__(self, ip, username, password):
self.device = {
"device_type": "cisco_ios",
"ip": ip,
"username": username,
"password": password,
}
self.connection = None
def connect(self):
print(f"Connecting to Cisco device {self.device['ip']}...")
self.connection = ConnectHandler(**self.device)
def disconnect(self):
if self.connection:
self.connection.disconnect()
print("Disconnected from Cisco device.")
def run_show_command(self, command):
if not self.connection:
raise Exception("Not connected to device.")
output = self.connection.send_command(command)
return output
def push_config(self, commands):
if not self.connection:
raise Exception("Not connected to device.")
output = self.connection.send_config_set(commands)
return output
Step 3: Juniper Module (juniper_module.py
)
from netmiko import ConnectHandler
class JuniperDevice:
def __init__(self, ip, username, password):
self.device = {
"device_type": "juniper",
"ip": ip,
"username": username,
"password": password,
}
self.connection = None
def connect(self):
print(f"Connecting to Juniper device {self.device['ip']}...")
self.connection = ConnectHandler(**self.device)
def disconnect(self):
if self.connection:
self.connection.disconnect()
print("Disconnected from Juniper device.")
def run_show_command(self, command):
if not self.connection:
raise Exception("Not connected to device.")
output = self.connection.send_command(command)
return output
def push_config(self, commands):
if not self.connection:
raise Exception("Not connected to device.")
output = self.connection.send_config_set(commands)
return output
Step 4: Main Program (main.py
)
from network_devices.cisco_module import CiscoDevice
from network_devices.juniper_module import JuniperDevice
# Example credentials (replace with real device details)
cisco = CiscoDevice(ip="192.168.1.10", username="admin", password="cisco123")
juniper = JuniperDevice(ip="192.168.1.20", username="admin", password="juniper123")
# Connect to devices
cisco.connect()
juniper.connect()
# Run show commands
print("Cisco Version:")
print(cisco.run_show_command("show version"))
print("Juniper Interfaces:")
print(juniper.run_show_command("show interfaces terse"))
# Push configuration
print("Configuring Cisco...")
print(cisco.push_config(["hostname CiscoRouter", "interface loopback0", "ip address 1.1.1.1 255.255.255.255"]))
print("Configuring Juniper...")
print(juniper.push_config(["set system host-name JuniperRouter"]))
# Disconnect
cisco.disconnect()
juniper.disconnect()
What We Did
- Created a package (
network_devices
) with two modules inside. - Each module has a class (
CiscoDevice
,JuniperDevice
) with methods to:- Connect
- Disconnect
- Run show commands
- Push configuration
- The
main.py
script imports both modules and interacts with them seamlessly.
This demonstrates how packages scale your projects: you can easily add more vendors (Arista, Fortinet, etc.) just by creating new modules inside the package.
🧾 Conclusion
Python modules and packages are more than just technical features — they’re the foundation of writing clean, professional code. By splitting your scripts into logical pieces, you gain flexibility, reduce repetition, and set yourself up for success as your projects grow.
For networking engineers preparing for the Cisco DevNet Associate exam, mastering modules is a crucial step. Whether you’re using built-in modules like datetime
or creating your own, this skill will save you time and effort in every automation task you take on.
This was Part 015 of the Cisco DevNet Associate 200-901 DEVASC series. If you’d like to see modules in action, don’t forget to watch the accompanying YouTube tutorial where I walk through demos step by step. And as always, keep practicing — the more you apply these concepts, the more natural they’ll become.
References:
Cisco Certified DevNet Expert (v1.0) Equipment and Software List