Reading and Interpreting Python Scripts

1. Why Python Matters for CCNA

The CCNA exam introduced Python awareness to reflect the industry shift toward network automation. Network engineers increasingly use Python to configure devices, parse CLI output, generate reports, and automate repetitive tasks — work that used to take hours of manual CLI commands now runs in seconds.

The CCNA does not require you to write complex Python — it requires you to read and interpret simple scripts: understand what a script does, predict its output, and recognise common constructs like loops, functions, and dictionaries.

  Traditional networking:      Automated networking:
  Engineer → CLI → Router      Python script → SSH → Router
  (one device, one command)    (100 devices, all commands, 5 seconds)
    

Related pages: Network Protocols | SSH | SNMP | NTP | Network Automation Overview | Python for Networking | Ansible Overview | Python Netmiko Lab | Python NAPALM Lab

2. Basic Python Syntax

Indentation — Python's Block Structure

Python uses indentation (spaces or tabs) to define code blocks — there are no curly braces { }. This is the single most important syntax rule: wrong indentation causes an IndentationError and the script won't run. The standard is 4 spaces per indent level.

# Correct indentation
if 5 > 3:
    print("Five is greater")    # This is inside the if block (4 spaces)
    print("Still inside")       # Also inside the if block
print("Outside the if block")   # Back at column 0 = outside

# Wrong indentation — causes IndentationError
if 5 > 3:
print("Error!")                 # No indentation = IndentationError

Comments

Lines starting with # are comments — Python ignores them completely. They document what code does and are never executed. Reading comments is the fastest way to understand what an unfamiliar script is trying to accomplish.

# This entire line is a comment — not executed
x = 10          # Inline comment — only the part after # is ignored
print(x)        # Outputs: 10

Python vs Other Languages — Key Differences

FeaturePythonOther Languages (C, Java)
Code blocksIndentation (4 spaces)Curly braces { }
Statement endNewline (no semicolons needed)Semicolon ; required
Variable declarationNone — just assign (x = 5)Type declaration required (int x = 5;)
String quotesBoth "double" and 'single' workOften distinct
Case sensitivityYes — NamenameUsually yes

3. Variables and Data Types

Python variables are created by assignment — no type declaration needed. Python automatically detects the type based on the value assigned.

TypeDescriptionExampleNotes
intWhole numberage = 28No decimal point
floatDecimal numberheight = 1.75Has a decimal point
strText stringname = "John"In quotes (single or double)
boolTrue or Falseis_active = TrueCapital T/F; used in conditions
listOrdered, changeable collectionskills = ["Python", "Linux"]Square brackets; zero-indexed
dictKey-value pairs — ideal for device datadevice = {"host": "192.168.1.1", "type": "router"}Curly braces; access by key. Also used for JSON data.
tupleOrdered, unchangeable collectioncoords = (10, 20)Round brackets; immutable
NoneTypeAbsence of valueresult = NoneLike NULL in other languages
# Working with a list
skills = ["Python", "Networking", "Linux"]
print(skills[0])       # "Python"   — first item (index 0)
print(skills[-1])      # "Linux"    — last item (negative index)
print(skills[1:3])     # ["Networking", "Linux"] — slice (index 1 up to but not including 3)
print(len(skills))     # 3          — number of items

# Working with a dictionary
device = {"host": "192.168.1.1", "vendor": "Cisco", "type": "router"}
print(device["host"])         # "192.168.1.1"  — access by key
print(device.get("port", 22)) # 22             — get() with default value if key missing
device["location"] = "HQ"    # Add a new key-value pair

4. Operators

CategoryOperatorsExampleResult
Arithmetic+ - * / // % **10 // 3 / 10 % 3 / 2 ** 33 (floor div) / 1 (remainder) / 8 (power)
Comparison== != < > <= >=5 == 5 / 5 != 3True / True
Logicaland or notTrue and False / True or FalseFalse / True
Assignment= += -= *=x = 5; x += 3x is now 8
Membershipin not in"Python" in skillsTrue (if "Python" is in the list)
# Logical operators in practice
x = 10
print(x > 5 and x < 20)   # True  — both conditions must be True
print(x < 5 or x > 8)     # True  — at least one condition is True
print(not x == 10)         # False — reverses the boolean result

# Membership operator — very useful for checking list/dict contents
protocols = ["TCP", "UDP", "ICMP"]
if "TCP" in protocols:
    print("TCP is supported")   # This runs

5. Input and Output

# Output — print() can display multiple values with a separator
print("Hello, John")
print("IP:", "192.168.1.1", "Port:", 22)     # IP: 192.168.1.1 Port: 22
print(f"Device {device['host']} is online")  # f-string formatting

# Input — always returns a string; convert with int() or float() if needed
host = input("Enter device IP: ")            # User types: 192.168.1.1
timeout = int(input("Enter timeout (s): "))  # Convert to integer
print(f"Connecting to {host} with {timeout}s timeout")
CCNA exam tip: input() always returns a string, even if the user types a number. To use the value as a number, convert it: int(input("...")) or float(input("...")). Forgetting this causes TypeError when you try to do arithmetic on the result.

6. Control Flow — if / elif / else

Conditional statements let a script make decisions. Python evaluates each condition in order and executes only the first matching block.

# Basic if/elif/else
interface_status = "up"

if interface_status == "up":
    print("Interface is operational")
elif interface_status == "down":
    print("Interface is down — check cable")
elif interface_status == "admin-down":
    print("Interface was shut down by admin")
else:
    print("Unknown status")

# Checking numeric ranges
latency_ms = 45
if latency_ms < 20:
    print("Excellent")
elif latency_ms < 100:
    print("Acceptable")     # This runs (45 is between 20 and 100)
else:
    print("High latency — investigate")

The condition after if or elif must evaluate to True or False. Comparison operators (==, !=, <, >) all produce boolean results.

7. Loops — for and while

for Loops — Iterating Over a Sequence

# Iterate over a list
devices = ["router1", "switch1", "switch2"]
for device in devices:
    print("Connecting to:", device)
# Output:
# Connecting to: router1
# Connecting to: switch1
# Connecting to: switch2

# range() — generate a sequence of numbers
for i in range(5):          # 0, 1, 2, 3, 4
    print(i)

for i in range(1, 6):       # 1, 2, 3, 4, 5
    print(i)

for i in range(0, 10, 2):   # 0, 2, 4, 6, 8 (step = 2)
    print(i)

# Iterate over a dictionary
config = {"hostname": "R1", "ip": "10.0.0.1", "mask": "255.255.255.0"}
for key, value in config.items():
    print(f"{key}: {value}")

while Loops — Repeat While a Condition Is True

# Count down from 3
countdown = 3
while countdown > 0:
    print("Count:", countdown)
    countdown -= 1           # Equivalent to: countdown = countdown - 1
print("Done!")
# Output: Count: 3 / Count: 2 / Count: 1 / Done!

# Retry logic — common pattern in network automation scripts
attempts = 0
max_retries = 3
while attempts < max_retries:
    print(f"Attempt {attempts + 1}: Connecting...")
    attempts += 1
    # In real code: break out of loop if connection succeeds
Beware infinite loops: A while loop whose condition never becomes False runs forever. Always ensure the loop variable changes in the body — countdown -= 1 in the example above. Use break to exit a loop early, and continue to skip to the next iteration.

8. Functions — def and return

Functions group reusable code under a name. In network automation scripts, functions typically wrap common operations like connecting to a device via SSH, sending a command, or parsing output from show interfaces or show ip route.

# Define a function with parameters
def check_ping(host, count=4):        # count has a default value of 4
    """
    Checks if a host is reachable by ping.
    host:  IP address or hostname (string)
    count: number of pings to send (int, default 4)
    """
    print(f"Pinging {host} {count} times...")
    # (real code would use subprocess or a library)
    return True    # Simulated success

# Call the function
result = check_ping("192.168.1.1")       # Uses default count=4
result2 = check_ping("10.0.0.1", 2)     # Overrides count with 2

if result:
    print("Host is reachable")

# Function with return value — calculation example
def calculate_subnet_hosts(prefix_length):
    """Returns the number of usable hosts for a given prefix length."""
    total = 2 ** (32 - prefix_length)
    return total - 2           # Subtract network and broadcast

hosts = calculate_subnet_hosts(24)
print(f"/24 has {hosts} usable hosts")   # /24 has 254 usable hosts

Key rules: A function must be defined before it is called. Parameters in the function definition are local — they only exist inside the function. Use return to send a value back to the caller. Functions without return return None automatically.

9. Error Handling — try / except

Network scripts inevitably encounter errors: devices are unreachable, SSH credentials fail, timeout occurs, output format is unexpected. The try/except block lets the script handle these gracefully instead of crashing.

# Basic try/except
try:
    num = int(input("Enter a number: "))   # Could fail if user types letters
    result = 100 / num                     # Could fail if num is 0
    print("Result:", result)
except ValueError:
    print("Error: Please enter a valid number")
except ZeroDivisionError:
    print("Error: Cannot divide by zero")
except Exception as e:
    print(f"Unexpected error: {e}")        # Catches anything else
finally:
    print("This always runs — use for cleanup")

# Common networking error pattern
import socket
try:
    socket.create_connection(("192.168.1.1", 22), timeout=3)
    print("SSH port is open")
except socket.timeout:
    print("Connection timed out — device unreachable")
except ConnectionRefusedError:
    print("Port 22 closed or SSH not running")
ExceptionWhen It Occurs
ValueErrorWrong type conversion — int("abc")
ZeroDivisionErrorDivision by zero — 10 / 0
KeyErrorDictionary key doesn't exist — d["missing"]
IndexErrorList index out of range — lst[99] on a short list
FileNotFoundErrorOpening a file that doesn't exist
ExceptionCatches any exception (use as a last resort catch-all)

10. Importing Modules

Python's power for network automation comes from its rich library ecosystem. The import statement loads a module (built-in, installed, or custom) making its functions and classes available in your script.

# Import an entire module
import math
print(math.sqrt(16))       # 4.0
print(math.pi)             # 3.14159...

# Import specific items from a module
from os import getcwd, listdir
print(getcwd())            # Current working directory

# Import with an alias (shorter name)
import json as j
data = j.loads('{"host": "192.168.1.1"}')
print(data["host"])        # 192.168.1.1

# Networking-relevant standard library modules
import socket              # Low-level network connections
import subprocess          # Run OS commands (ping, traceroute)
import re                  # Regular expressions for parsing CLI output
import json                # Parse JSON-format API responses — see JSON, XML & YANG
import time                # Delays between commands (time.sleep(1))

The json module is particularly important for parsing responses from REST APIs and RESTCONF/NETCONF interfaces. See JSON, XML & YANG for the data format context, and REST API Overview for how Python scripts interact with network device APIs.

Popular networking automation libraries (installed via pip):
LibraryPurposeInstall
NetmikoSSH to Cisco/multi-vendor devices; send commands and parse output. See Python Netmiko Lab.pip install netmiko
ParamikoLow-level SSH library — foundation for Netmikopip install paramiko
NAPALMVendor-neutral network device management API. See Python NAPALM Lab.pip install napalm
requestsHTTP/REST API calls — for Cisco DNA Center, Meraki, NSO. Used with RESTCONF.pip install requests
nmapNetwork scanning from Pythonpip install python-nmap

11. Common Built-in Functions and Data Manipulation

FunctionPurposeExampleOutput
len()Number of items in a list, string, or dictlen(["a", "b", "c"])3
range()Generate a numeric sequencelist(range(1, 4))[1, 2, 3]
type()Get the data type of a variabletype(3.14)<class 'float'>
int()Convert to integerint("42")42
str()Convert to stringstr(192)"192"
print()Output to screenprint("IP:", ip)IP: 10.0.0.1
sorted()Return sorted listsorted([3,1,2])[1, 2, 3]
enumerate()Loop with index and valuefor i, v in enumerate(lst)i=0,v=item1 etc.

String Operations

hostname = "router-01.hq.example.com"
print(hostname.upper())            # "ROUTER-01.HQ.EXAMPLE.COM"
print(hostname.lower())            # "router-01.hq.example.com"
print(hostname.split("."))         # ["router-01", "hq", "example", "com"]
print(hostname.startswith("router")) # True
print(hostname.replace("-", "_"))  # "router_01.hq.example.com"
print(f"Hostname: {hostname}")     # f-string: inserts variable into text

List and Dictionary Operations

# List operations
interfaces = ["Gi0/0", "Gi0/1", "Gi0/2"]
interfaces.append("Gi0/3")         # Add item to end
interfaces.remove("Gi0/1")         # Remove specific item
print(interfaces[0])               # "Gi0/0" — first item (index 0)
print(interfaces[-1])              # "Gi0/3" — last item

# Dictionary operations — similar structure to JSON API responses
device = {"hostname": "R1", "ip": "10.0.0.1"}
device["os"] = "IOS-XE"            # Add new key
print(device.keys())               # dict_keys(["hostname", "ip", "os"])
print(device.values())             # dict_values(["R1", "10.0.0.1", "IOS-XE"])
print("hostname" in device)        # True — key exists check

Python dictionaries map directly to JSON objects — when you receive a response from a REST API or RESTCONF endpoint, json.loads() converts it to a Python dictionary you can loop over and query by key.

12. Reading a Complete Networking Script

Here is a realistic script showing how all the concepts work together. Read through it and use the annotation to understand each part. This pattern — checking SSH port reachability across a list of devices — is a common first step in network automation. For a full Netmiko-based implementation, see Python Netmiko Lab.

# network_checker.py
# Purpose: Check reachability of a list of network devices
# Author: NetsTuts Team

import socket                              # 1. Import standard library
import time                               # 2. For delays between checks

def check_ssh_port(host, port=22, timeout=3):
    """
    Tests if SSH port is open on a device.
    Returns True if reachable, False if not.
    """
    try:                                   # 3. Error handling
        conn = socket.create_connection((host, port), timeout=timeout)
        conn.close()
        return True                        # 4. Return value
    except (socket.timeout, ConnectionRefusedError, OSError):
        return False

# 5. List of devices to check
devices = [
    {"name": "Core-Router", "ip": "10.0.0.1"},
    {"name": "Dist-Switch", "ip": "10.0.0.2"},
    {"name": "Access-SW1",  "ip": "10.0.1.1"},
]

reachable = []                             # 6. Empty list to collect results
unreachable = []

for device in devices:                     # 7. Loop over list of dicts
    name = device["name"]                  # 8. Access dict values by key
    ip   = device["ip"]

    if check_ssh_port(ip):                 # 9. Call function, check result
        reachable.append(name)             # 10. Append to list
        print(f"  OK  {name} ({ip})")
    else:
        unreachable.append(name)
        print(f"  !! {name} ({ip}) UNREACHABLE")

    time.sleep(0.5)                        # 11. Wait 0.5 seconds between checks

# 12. Summary output
print(f"\nReachable:   {len(reachable)} devices")
print(f"Unreachable: {len(unreachable)} devices")
if unreachable:
    print("Devices to investigate:", unreachable)
Script walkthrough — numbered annotations:
  1. import socket — loads the socket module for network connections
  2. import time — loads the time module for sleep/delay
  3. try/except — handles connection failures gracefully without crashing
  4. return True/False — function sends result back to the caller
  5. devices list — a list of dictionaries, each describing one device
  6. reachable = [] — empty list initialised before the loop
  7. for device in devices — iterates over each dictionary in the list
  8. device["name"] — accesses a value from the current dict by key
  9. if check_ssh_port(ip): — calls the function; True = device reachable
  10. reachable.append(name) — adds the device name to the results list
  11. time.sleep(0.5) — pauses 0.5 seconds to avoid overwhelming devices
  12. len(reachable) — counts items in the list for the summary

13. Key Points and Exam Tips

  • Indentation is mandatory — Python uses 4 spaces per level. Mixing tabs and spaces causes errors. Wrong indentation changes what code is inside a block.
  • List indexing starts at 0skills[0] is the first item, skills[-1] is the last.
  • Dictionary access by keydevice["hostname"] returns the value for key "hostname". Using a non-existent key raises KeyError; use .get("key", default) to avoid this. Dictionaries are the Python equivalent of JSON objects.
  • range(n) produces 0 to n-1range(3) gives 0, 1, 2 (not 1, 2, 3).
  • Functions must be defined before calling — Python reads files top to bottom.
  • input() always returns a string — convert with int() or float() for numeric operations.
  • Type matters"5" + "3" gives "53" (string concatenation); 5 + 3 gives 8 (addition).
  • Read comments first — when interpreting an unfamiliar script, start by reading all # comments to understand the purpose before reading the code.
  • Python scripts use SSH (via Netmiko/Paramiko) or REST APIs (via requests) to interact with network devices. See Python for Networking for the broader context.
  • For hands-on automation: Python Netmiko Lab | Python NAPALM Lab | Ansible IOS Lab.

Python Script Interpretation Quiz

1. In Python, how are code blocks (e.g., inside an if statement or function) defined?

Correct answer is A. Python uses indentation — not curly braces — to define code blocks. Every line inside a block must be indented to the same level (4 spaces is standard). If the indentation is wrong or inconsistent, Python raises an IndentationError and the script will not run. This is Python's most distinctive syntax feature compared to languages like C, Java, or JavaScript. See Network Automation Overview for why Python has become the standard tool for network scripting.

2. What does the # symbol denote in a Python script?

Correct answer is D. Everything after a # on the same line is a comment — Python's interpreter skips it completely and does not execute it. Comments exist solely for humans reading the code. When interpreting an unfamiliar script, reading the comments first is the fastest way to understand the script's purpose without having to analyse every line of code.

3. Which Python data type stores decimal (floating-point) numbers?

Correct answer is B. The float data type stores decimal numbers (e.g., latency = 1.5, pi = 3.14159). int stores whole numbers with no decimal. bool stores True or False. str stores text. Use type(variable) to check the type of any variable at runtime — e.g., type(3.14) returns <class 'float'>.

4. What is the output of print(5 == 5)?

Correct answer is C. The == operator is a comparison operator (not assignment). It compares two values and returns a boolean: True if they are equal, False if not. Since 5 equals 5, the expression evaluates to True, and print(True) outputs True. Note the difference: x = 5 assigns 5 to x, while x == 5 tests whether x equals 5.

5. Which logical operator returns True if at least one of the conditions is True?

Correct answer is A. The or operator returns True if at least one operand is True. and requires both to be True. not inverts a single boolean. Exam tip — truth table: True or False = True; True and False = False; not True = False. These operators are heavily used in if conditions to combine multiple checks in automation scripts.

6. What does for i in range(3): print(i) output?

Correct answer is D. range(3) generates the sequence 0, 1, 2 — starting at 0 and going up to but not including 3. The loop runs 3 times printing each value. To start from 1 and include 3: use range(1, 4). To step by 2: range(0, 10, 2) gives 0, 2, 4, 6, 8. The range() function is zero-indexed by default — this catches many beginners off guard.

7. Which keyword is used to define a function in Python?

Correct answer is B. Python uses def to define a function: def function_name(parameters): followed by an indented body. The function body must be indented. Use return value to send a result back to the caller. Functions without return automatically return None. Functions must be defined before they are called — Python reads files top to bottom. In network automation scripts, functions typically wrap operations like SSH connections or output parsing.

8. What is the purpose of a try/except block in Python?

Correct answer is C. A try/except block wraps code that might fail at runtime. Python attempts the try block; if an exception occurs, execution jumps immediately to the matching except block instead of crashing. In network automation this is essential — SSH connections timeout, devices refuse connections, or output doesn't match expectations. You can catch specific exceptions (except ValueError) or any exception (except Exception as e). The optional finally block runs regardless of whether an exception occurred.

9. Which Python keyword imports an external module or library into a script?

Correct answer is A. Python uses import module_name to load an entire module, or from module import function to import specific items. You can also alias with import json as j. Networking scripts commonly import: socket (connections), subprocess (run OS commands), re (regex parsing), json (API responses — see JSON, XML & YANG), time (delays), and third-party libraries like netmiko for SSH device management (see Python Netmiko Lab).

10. What is the output of this script?
numbers = [2, 4, 6]
total = 0
for n in numbers:
    total += n
print("Total:", total)

Correct answer is D. Tracing through the script step by step: total starts at 0. The for loop iterates over [2, 4, 6]. First iteration: total += 2 → total = 2. Second: total += 4 → total = 6. Third: total += 6 → total = 12. After the loop, print("Total:", 12) outputs Total: 12. This accumulator pattern — initialise a variable before a loop and update it inside — is one of the most common patterns in Python scripts, including network automation scripts that collect results from multiple devices.

← Back to Home