IOS is already a strict, indentation‑sensitive language. The hierarchical config written under interface GigabitEthernet0/1 only makes sense because of how it’s nested. Python works on the same idea — except instead of pressing Tab for visual clarity, the indentation is the syntax. Today covers the handful of rules that account for nine out of ten beginner mistakes, and the payoff is being able to read other people’s scripts without panic.
This is Day 2 of the 21‑post Python for Network Engineers series. Day 1 covered installing Python 3.11+ in a virtualenv — every example below assumes a working python prompt with the >>> REPL.
Variables: no var, no type, no semicolon
Assignment uses =. That’s it. There is no declaration keyword (var, let, my) and no need to declare a type up front.
hostname = "core-sw01"
mgmt_ip = "10.0.0.1"
uptime_days = 47
is_reachable = True
Names are case‑sensitive — hostname and Hostname are different variables. The convention is snake_case for variables and functions, CONSTANT_CASE for values that never get reassigned, and CamelCase for class names (classes come much later and aren’t needed yet).
Python infers the type from the value, but each variable does have a type at any given moment. Ask with type():
>>> type(hostname)
<class 'str'>
>>> type(uptime_days)
<class 'int'>
>>> type(is_reachable)
<class 'bool'>
The five primitive types used every day
| Type | Example | What it represents |
|---|---|---|
int |
1500 |
Whole numbers — MTU, port numbers, AS numbers |
float |
0.5 |
Decimals — interface load, latency in ms |
str |
"GigabitEthernet0/1" |
Text — hostnames, interface names, IPs (as text) |
bool |
True |
True or False, capitalized — link up/down, reachable/not |
NoneType |
None |
“No value” — closer to IOS’s “not configured” than to 0 or "" |
Cisco context: None trips up people coming from C or Go, where 0 or an empty string serves as a sentinel. In Python, “this OSPF cost has not been set” is None, not 0 — because 0 is a perfectly valid OSPF cost.
Strings — single, double, triple, f‑string
Single and double quotes are interchangeable. Pick one and stay consistent — most projects pick double:
banner = "Authorized access only"
warning = 'Do not use single quotes if the string contains "double quotes"'
Triple quotes preserve newlines — perfect for multi‑line config snippets:
snippet = """interface GigabitEthernet0/1
description Uplink to core
ip address 10.0.0.1 255.255.255.0
no shutdown
"""
And the most useful string form for network work — the f‑string, prefix f, anything in {} is evaluated:
vlan = 100
desc = "Voice"
print(f"vlan {vlan}\n name {desc}")
# vlan 100
# name Voice
f‑strings show up constantly — for building config, for log lines, for messages. Day 3 is dedicated entirely to them.
Indentation IS the syntax
This is the rule that surprises everyone coming from C, Java, or Perl: there are no { } braces and no end keyword. A block is defined purely by indentation.
if uptime_days > 30:
print("This box has been up a while")
print("Consider a maintenance reload")
print("This always runs")
The two indented lines belong to the if. The third line, at the same level as if, does not. The convention is 4 spaces per level — never tabs, never mixed. Configure the editor to insert 4 spaces on Tab. Mixing tabs and spaces produces IndentationError: unexpected indent and an hour of confusion.
The colon : at the end of if, for, while, def, and class is required. It signals “an indented block follows.” Forgetting it produces SyntaxError: expected ':' — one of the friendlier error messages of the week.
Comments and docstrings
# Single-line comment — anything after # to end of line.
mtu = 9000 # inline comment, also fine
"""Triple-quoted string used as a module or function docstring.
Python treats this as documentation, not just a comment, and tools
like help() pick it up automatically."""
Same rule as in IOS: comments should explain the why, not the what. # set MTU to 9000 adds nothing the next line doesn’t already say. # jumbo frames required by storage VLAN per ticket NET-447 earns its keep.
Operators that behave differently than expected
=assigns.==compares. Confusing them is the single most common bug in week one./always returns a float, even when the math is exact:10 / 2 == 5.0. Use//for integer division.and/or/notare the boolean operators — written as words, not&&/||/!.+on strings concatenates:"Gig" + "0/1" == "Gig0/1". It does not work on a string and a number — that raises aTypeError.
link_speed_mbps = 1000
print("Speed: " + str(link_speed_mbps) + " Mbps") # works, but ugly
print(f"Speed: {link_speed_mbps} Mbps") # better
Truthiness — what counts as “true enough”
Python treats more than just True as truthy in an if. Falsy values are: False, None, 0, 0.0, "" (empty string), [] (empty list), {} (empty dict). Everything else is truthy.
interfaces = []
if interfaces:
print("Found interfaces")
else:
print("No interfaces yet") # this branch runs
This is why Python code rarely says if len(x) > 0: — it just says if x: and lets the empty container be falsy.
Reading errors instead of fearing them
Python’s tracebacks look intimidating, but they read bottom‑up. The last line is always the actual error, and the line above names the file and line number where it happened. Reading them in that order — type, then location, then everything else — makes them far less scary.
Traceback (most recent call last):
File "switch_check.py", line 4, in <module>
print("Speed: " + speed_mbps + " Mbps")
TypeError: can only concatenate str (not "int") to str
Three lines say it all: a TypeError (a string added to an int), at line 4 of switch_check.py, in the print(...) call. Fix the line, re‑run.
Putting it together: a tiny script
Saved as day2.py and run with python day2.py:
hostname = "edge-rtr01"
uptime_days = 142
is_reachable = True
if is_reachable and uptime_days > 90:
print(f"{hostname} has been up for {uptime_days} days — overdue for a reload window")
elif is_reachable:
print(f"{hostname} reachable, uptime healthy")
else:
print(f"{hostname} not reachable — check console")
Read top to bottom, note the details: no semicolons, no braces, the colon at the end of each if/elif/else, the four‑space indentation, and the f‑string interpolating two variables into one message. Every Python script in this series uses these same shapes.
Exercises
- In the REPL, create a variable
mtuset to1500, then print the message"MTU is 1500 bytes"using an f‑string. - What does
type(10 / 5)print, and why? What abouttype(10 // 5)? - Predict what this prints before running it:
interface = "" if interface: print("got interface") else: print("no interface name") - Fix this broken snippet so it runs without errors:
port_count = 48 print("Switch has " + port_count + " ports") - Stretch: write three lines that store an interface name, an admin status (boolean), and a description. Then print one line that reads
"<name>: <up/down> - <description>"using an f‑string and a conditional expression (search “Python ternary” for the syntax).
Answers
Show answer 1
>>> mtu = 1500
>>> print(f"MTU is {mtu} bytes")
MTU is 1500 bytes
Show answer 2
type(10 / 5) is <class 'float'> because / always returns a float in Python 3, even when the math divides evenly. type(10 // 5) is <class 'int'> because // is integer (floor) division and preserves the int type.
Show answer 3
Prints no interface name. An empty string "" is falsy, so the if branch is skipped and the else runs. This is the idiomatic Python way to test “is there a non‑empty value?”
Show answer 4
Two clean fixes — the f‑string version is preferred in real code:
port_count = 48
print(f"Switch has {port_count} ports") # idiomatic
# or, less cleanly:
print("Switch has " + str(port_count) + " ports") # explicit conversion
Python won’t auto‑convert int to str during + — it raises TypeError instead, which is by design. Implicit conversion is the source of half the world’s bugs.
Show answer 5
name = "Gi0/1"
admin_up = True
description = "Uplink to core"
print(f"{name}: {'up' if admin_up else 'down'} - {description}")
# Gi0/1: up - Uplink to core
The 'up' if admin_up else 'down' is Python’s ternary expression — it evaluates to one of the two strings depending on the boolean. Useful any time an A‑or‑B choice belongs inside an f‑string.
Coming tomorrow
Day 3: Strings, f‑strings & Slicing — Parsing IPs, MACs, and Banner Output. Messy CLI output gets chopped, split, and reformatted with nothing but built‑in string methods. By the end of tomorrow, extracting the second octet of an IP, normalizing a Cisco MAC like aabb.ccdd.eeff into colon notation, and trimming a banner motd all take three lines.